目录
[2.equals ⽅法:按照字典序⽐较](#2.equals ⽅法:按照字典序⽐较)
[3.compareTo ⽅法:按照字典序进⾏⽐较](#3.compareTo ⽅法:按照字典序进⾏⽐较)
[4.compareToIgnoreCase ⽅法:与compareTo⽅式相同,但是忽略⼤⼩写⽐较](#4.compareToIgnoreCase ⽅法:与compareTo⽅式相同,但是忽略⼤⼩写⽐较)
内容大纲:
本文介绍了Java中String类的重要性和基本原理。String类解决了C语言字符串操作的不足,采用面向对象方式封装字符串功能。文章详细讲解了String的构造方法、字符串常量池机制、内存存储方式,以及常用操作方法(比较、查找、转换、替换、拆分等)。同时阐述了String的不可变性特点,并推荐使用StringBuilder和StringBuffer进行高效字符串修改。最后对比了StringBuffer(线程安全)和StringBuilder(非线程安全)的差异,提供了完整的字符串处理解决方案。
一:String类的重要性
在C语⾔中已经涉及到字符串了,但是在C语⾔中要表⽰字符串只能使⽤字符数组或者字符指针,可以 使⽤标准库提供的字符串系列函数完成⼤部分操作,但是这种将数据和操作数据⽅法分离开的⽅式不 符合⾯向对象的思想,⽽字符串应⽤⼜⾮常⼴泛,因此Java语⾔专⻔提供了String类。
二:String原理介绍
1.字符串构造
String类提供的构造⽅式⾮常多,常⽤的就以下三种:
java
public class Test {
public static void main(String[] args) {
//使⽤字符串常量进⾏赋值
String s1 = "hello";
System.out.println(s1);
//直接new String对象
String s2= new String("hello ");
System.out.println(s2);
//使⽤字符数组进⾏构造
char[] arry = {'h','e','l','l','o'};
String s3 = new String(arry);
//使⽤字节数组构造对象
byte[] bytes = {91,92,93,94};
String s4 = new String(bytes);
System.out.println(s4);
}
}
输出:

其他构造⽅法需要⽤到时,⼤家参考Java在线⽂档:
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html
查看String源码,我们观察到:String是引⽤类型,内部并不存储字符串本⾝。

2.字符串常量池(StringTable)
想要了解字符串的布局,我们⾸先得了解⼀个新的内存叫做:字符串常量池(StringTable).
字符串常量池在JVM中是String Table类,实际是⼀个固定⼤⼩的HashTable(⼀种⾼效⽤来进⾏查找的数据结构,后续给⼤家详细介绍),不同JDK版本下字符串常量池的位置以及默认⼤⼩是不同的:

关于⽅法区、堆等内存结构的具体局部,后续JVM中会给⼤家详细介绍。
关于"池"的理解:
"池"是编程中的⼀种常⻅的,重要的提升效率的⽅式,我们会在未来的学习中遇到各种"内存池","线 程池","数据库连接池"....
⽐如:家⾥给⼤家打⽣活费的⽅式
1.家⾥经济拮据,每⽉定时打⽣活费,有时可能会晚,最差情况下可能需要向家⾥张⼝要,速度慢
2.家⾥有矿,⼀次性打⼀年的⽣活费放到银⾏卡中,⾃⼰随⽤随取,速度⾮常快
⽅式2,就是池化技术的⼀种⽰例,钱放在卡上,随⽤随取,效率⾮常⾼。常⻅的池化技术⽐如:数 据库连接池、线程池等。
3.字符串内存存储
java
public static void main(String[] args) {
String s1 = "abc";
String s2 = "abc";
System.out.println(s1==s2);
}

说明:
1.s1在进⾏存储的时候,"abc"会先存储到字符串常量池当中
2.当s2再次存储的时候,先会检查字符串常量池当中是否存在"abc"常量,如果存在,则不再重复 存储
java
public static void main(String[] args) {
String s1 = new String("abc");
String s2 =new String("abc");
System.out.println(s1==s2);
}

说明:
1.第⼀次存储的时候,会将"abc"存储到常量池当中
2.每次new都会在堆中实例化新的对象
3.存储s2的时候,会使⽤常量池的"abc"对象进⾏存储
三:常⽤⽅法介绍
1.String对象的⽐较
字符串的⽐较是常⻅操作之⼀,⽐如:当你登录⼀个⽹站的时候,输⼊了⽤⼾名和密码之后,需要后 台进⾏⽐较和对⽐。
1.==⽐较是否引⽤同⼀个对象
注意:对于内置类型,==⽐较的是变量中的值;对于引⽤类型==⽐较的是引⽤中的地址。
java
public static void main(String[] args) {
int a = 10;
int b = 20;
int c = 10;
//对于基本类型变量,==⽐较两个变量中存储的值是否相同
System.out.println(a==c);
System.out.println(a==b);
//对于引⽤类型变量,==/⽐较两个引⽤变量引⽤的是否为同⼀个对象
String s1=new String("hello");
String s2=new String("world");
String s3=new String("hello");
String s4=s1;
System.out.println(s1==s2);
System.out.println(s1==s3);
System.out.println(s1==s4);
}
输出:

2.equals ⽅法:按照字典序⽐较
字典序:字符⼤⼩的顺序
String类重写了⽗类Object中equals⽅法,Object中equals默认按照==⽐较,String重写equals⽅法 后,按照如下规则进⾏⽐较,⽐如: s1.equals(s2)
JDK17当中的源码部分:

使用:
java
public static void main(String[] args) {
String s1=new String("hello");
String s2=new String("hello");
String s3=new String("ccccc");
System.out.println(s1==s2);
System.out.println(s1==s3);
System.out.println(s1.equals(s2));
System.out.println(s1.equals(s3));
}
输出:

3.compareTo ⽅法:按照字典序进⾏⽐较
与equals不同的是,equals返回的是boolean类型,⽽compareTo返回的是int类型。具体⽐较⽅式:
-
先按照字典次序⼤⼩⽐较,如果出现不等的字符,直接返回这两个字符的⼤⼩差值
-
如果前k个字符相等(k为两个字符⻓度最⼩值),返回值两个字符串⻓度差值
java
public static void main(String[] args) {
String s1 = new String("abc");
String s2 = new String("ac");
String s3 = new String("abc");
String s4 = new String("abcdef");
System.out.println(s1.compareTo(s2)); //不同输出字符差值-1
System.out.println(s1.compareTo(s3)); //相同输出0
System.out.println(s1.compareTo(s4)); //前k个字符完全相同,输出⻓度差值-3
}
输出:

4.compareToIgnoreCase ⽅法:与compareTo⽅式相同,但是忽略⼤⼩写⽐较
java
public static void main(String[] args) {
String s1 = new String("abc");
String s2 = new String("ac");
String s3 = new String("abc");
String s4 = new String("abcdef");
System.out.println(s1.compareToIgnoreCase(s2));
System.out.println(s1.compareToIgnoreCase(s3));
System.out.println(s1.compareToIgnoreCase(s4));
}
输出:

2.字符串查找
字符串查找也是字符串中⾮常常⻅的操作,String类提供的常⽤查找的⽅法:
| 方法 | 功能 |
|---|---|
| char charAt(int index) | 返回 index 位置上字符,如果 index 为负数或者越界,抛出 IndexOutOfBoundsException 异常 |
| int indexOf(int ch) | 返回 ch 第一次出现的位置,没有返回 -1 |
| int indexOf(int ch, int fromIndex) | 从 fromIndex 位置开始找 ch 第一次出现的位置,没有返回 -1 |
| int indexOf(String str) | 返回 str 第一次出现的位置,没有返回 -1 |
| int indexOf(String str, int fromIndex) | 从 fromIndex 位置开始找 str 第一次出现的位置,没有返回 -1 |
| int lastIndexOf(int ch) | 从后往前找,返回 ch 第一次出现的位置,没有返回 -1 |
| int lastIndexOf(int ch, int fromIndex) | 从 fromIndex 位置开始找,从后往前找 ch 第一次出现的位置,没有返回 -1 |
| int lastIndexOf(String str) | 从后往前找,返回 str 第一次出现的位置,没有返回 -1 |
| int lastIndexOf(String str, int fromIndex) | 从 fromIndex 位置开始找,从后往前找 str 第一次出现的位置,没有返回 -1 |
代码:
java
public class StringSearchExample {
public static void main(String[] args) {
// 定义一个测试字符串,方便观察索引位置
// 索引: 0123456789...
String text = "Hello World, Hello Java";
System.out.println("测试字符串: \"" + text + "\"");
System.out.println("-----------------------------------");
// 1. char charAt(int index)
// 功能:返回指定索引处的字符
char c = text.charAt(1);
System.out.println("1. charAt(1): " + c); // 输出 'e'
// 2. int indexOf(int ch)
// 功能:返回指定字符第一次出现的索引
int idx1 = text.indexOf('o');
System.out.println("2. indexOf('o'): " + idx1); // 输出 4 (World中的o)
// 3. int indexOf(int ch, int fromIndex)
// 功能:从指定索引开始,返回字符第一次出现的索引
int idx2 = text.indexOf('o', 5);
System.out.println("3. indexOf('o', 5): " + idx2); // 输出 7 (Java前的o,跳过了第一个)
// 4. int indexOf(String str)
// 功能:返回指定子字符串第一次出现的索引
int idx3 = text.indexOf("Hello");
System.out.println("4. indexOf(\"Hello\"): " + idx3); // 输出 0
// 5. int indexOf(String str, int fromIndex)
// 功能:从指定索引开始,返回子字符串第一次出现的索引
int idx4 = text.indexOf("Hello", 1);
System.out.println("5. indexOf(\"Hello\", 1): " + idx4); // 输出 13 (第二个Hello)
// 6. int lastIndexOf(int ch)
// 功能:返回指定字符最后一次出现的索引(从后往前找)
int idx5 = text.lastIndexOf('l');
System.out.println("6. lastIndexOf('l'): " + idx5); // 输出 22 (Java中的l)
// 7. int lastIndexOf(int ch, int fromIndex)
// 功能:从指定索引开始向前搜索,返回字符最后一次出现的索引
int idx6 = text.lastIndexOf('l', 10);
System.out.println("7. lastIndexOf('l', 10): " + idx6); // 输出 3 (Hello中的第二个l,因为限制了范围在10以内)
// 8. int lastIndexOf(String str)
// 功能:返回指定子字符串最后一次出现的索引
int idx7 = text.lastIndexOf("Hello");
System.out.println("8. lastIndexOf(\"Hello\"): " + idx7); // 输出 13
// 9. int lastIndexOf(String str, int fromIndex)
// 功能:从指定索引开始向前搜索,返回子字符串最后一次出现的索引
int idx8 = text.lastIndexOf("Hello", 12);
System.out.println("9. lastIndexOf(\"Hello\", 12): " + idx8); // 输出 0 (因为在索引12之前只有一个Hello)
// 补充:未找到时的返回值
System.out.println("-----------------------------------");
System.out.println("indexOf('z'): " + text.indexOf('z')); // 输出 -1
}
}
3.转换
1.数字和字符串转化
java
class NumberStringConvert {
public static void main(String[] args) {
// ================= 1. 数字转字符串 =================
System.out.println("========== 数字转字符串 ==========");
int num = 12345;
double pi = 3.14159;
// 方法一:使用 String.valueOf() 【最推荐,通用且安全】
String str1 = String.valueOf(num);
System.out.println("1. String.valueOf(num): " + str1);
// 方法二:使用包装类的 toString() 方法
String str2 = Integer.toString(num);
String str3 = Double.toString(pi);
System.out.println("2. Integer.toString(num): " + str2);
System.out.println(" Double.toString(pi): " + str3);
// ================= 2. 字符串转数字 =================
System.out.println("\n========== 字符串转数字 ==========");
String intStr = "67890";
String doubleStr = "98.76";
// 方法一:使用包装类的 parseXxx() 方法 【最常用,返回基本数据类型】
int parsedInt = Integer.parseInt(intStr);
double parsedDouble = Double.parseDouble(doubleStr);
System.out.println("1. parseInt / parseDouble 结果: " + (parsedInt + 1) + ", " + (parsedDouble + 1));
// 方法二:使用包装类的 valueOf() 方法 (返回包装类对象,如 Integer, Double)
Integer intObj = Integer.valueOf(intStr);
System.out.println("2. Integer.valueOf 结果: " + (intObj + 1));
}
}
输出:

2.⼤⼩写转换
java
public static void main(String[] args) {
String s1 = "hello";
String s2 = "HELLO";
//⼩写转⼤写
System.out.println(s1.toUpperCase());
//大写转小写
System.out.println(s2.toLowerCase());
}
输出:

3.字符串转数组
java
public static void main(String[] args) {
// ================= 1. 字符串转数组 =================
String word = "Hello";
char[] chars = word.toCharArray();
System.out.println("转为数组: " + Arrays.toString(chars));
// ================= 2. 数组转字符串 =================
String[] names = {"张三", "李四", "王五"};
String joinedStr2 = Arrays.toString(names);
System.out.println("转为字符串: " + joinedStr2);
}
输出:

4.格式化
java
public static void main(String[] args) {
String word = "Hello";
String s = String.format("%d-%d-%d", 2019, 9,14);
System.out.println(s);
}
输出:

4.字符串的替换
使⽤⼀个指定的新的字符串替换掉已有的字符串数据,可⽤的⽅法如下:

java
public static void main(String[] args) {
String str = "helloworld" ;
System.out.println(str.replaceAll("l", "_"));
System.out.println(str.replaceFirst("l", "_"));
}
输出:

5.字符串的拆分
可以将⼀个完整的字符串按照指定的分隔符划分为若⼲个⼦字符串。
可⽤⽅法如下:

实现字符串的拆分处理
java
public static void main(String[] args) {
String str = "hello world hello bit" ;
String[] result = str.split(" ") ; //按照空格拆分
for(String s: result) {
System.out.println(s);
}
}
输出:

字符串的部分拆分(把内容分成多少份)
java
public static void main(String[] args) {
String str = "hello world hello bit" ;
String[] result = str.split(" ",2) ;
for(String s: result) {
System.out.println(s);
}
}
输出:

拆分是特别常⽤的操作.⼀定要重点掌握.另外有些特殊字符作为分割符可能⽆法正确切分,需要加上转 义.
6.字符串截取
从⼀个完整的字符串之中截取出部分内容。可⽤⽅法如下:

java
public static void main(String[] args) {
String str = "helloworld" ;
System.out.println(str.substring(5));
System.out.println(str.substring(0, 5));
}
输出:

注意事项:
1. 索引从0开始
2. 注意前闭后开区间的写法,substring[0,5)表⽰包含0号下标的字符,不包含5号下标
7.去除左右两边的空格

java
public static void main(String[] args) {
String str = " hello world " ;
System.out.println("["+str+"]");
System.out.println("["+str.trim()+"]");
}
输出:

8.intern⽅法
当调⽤ intern() ⽅法时,如果字符串常量池中已经包含⼀个等于此String对象的字符串(由 equals(Object)⽅法确定),则返回常量池中的字符串。
否则,将此String对象添加到常量池中,并返回此String对象的引⽤。
java
public static void main(String[] args) {
char[] ch = new char[]{'a', 'b', 'c'};
String s1 = new String(ch); // s1对象并不在常量池中
s1.intern();
String s2 = "abc"; //"abc"在常量池中存在
System.out.println(s1 == s2);
}
输出:


注意:
1.如果不加s1.intern(); 输出的值是false
2.如果加了,则输出true
四:字符串的不可变性
String是⼀种不可变对象. 字符串中的内容是不可改变。字符串不可被修改,是因为:
1. String类在设计时就是不可改变的,String类实现描述中已经说明了
2. 所有涉及到可能修改字符串内容的操作都是创建⼀个新对象,改变的是新对象
3. String之所以不可以被修改的原因是内部数组因为为私有成员
五:字符串修改
对于String类本⾝来说,是不可以修改的。形如如下代码:
java
public static void main(String[] args) {
String s = "hello";
s = s + " world";
System.out.println(s);
}
输出:

在这个例⼦中, s + " world" 创建了⼀个新的String对象,⽽原来的"Hello"对象保持不变.对于 String的拼接来说,如果是在循环当中会产⽣很多的临时对象。此时Java提供了StringBuffer和 StringBuilder。
1.StringBuilder的介绍
由于String的不可更改特性,为了⽅便字符串的修改,Java中⼜提供StringBuilder和StringBuffer类。 这两个类⼤部分功能是相同的,这⾥介绍StringBuilder常⽤的⼀些⽅法,其它需要⽤到了⼤家可参阅
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/StringBuilder.html
| 方法 | 说明 |
|---|---|
| StringBuff append(String str) | 在尾部追加,相当于String的+=,可以追加:bool、double、float、int、long、Object、String、char等类型 |
| char charAt(int index) | 获取index位置的字符 |
| int length() | 获取字符串的长度 |
| int capacity() | 获取底层保存字符串空间总的大小 |
| void ensureCapacity(int mininimumCapacity) | 扩容 |
| void setCharAt(int index, char ch) | 将index位置的字符设置为ch |
| int indexOf(String str) | 返回str第一次出现的位置 |
| int indexOf(String str, int fromIndex) | 从fromIndex位置开始查找str第一次出现的位置 |
| int lastIndexOf(String str) | 返回最后一次出现str的位置 |
| int lastIndexOf(String str, int fromIndex) | 从fromIndex位置开始找str最后一次出现的位置 |
| StringBuff insert(int offset, String str) | 在offset位置插入:八种基类类型 & String类型 |
| StringBuffer deleteCharAt(int index) | 删除index位置字符 |
| StringBuffer delete(int start, int end) | 删除[start, end)区间内的字符 |
| StringBuffer replace(int start, int end, String str) | 将[start, end)位置的字符替换为str |
| String substring(int start) | 从start开始一直到末尾的字符以String的形式返回 |
| String substring(int start, int end) | 将[start, end)范围内的字符以String的形式返回 |
| StringBuffer reverse() | 反转字符串 |
| String toString() | 将所有字符按照String的方式返回 |
2.StringBuffer的介绍
StringBuffer和StringBuilder从⽅法的功能上来说没有太⼤区别,这⾥不做单独介绍,可以查看官⽅⽂ 档:
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/StringBuffer.html
StringBuffer采⽤同步处理,属于线程安全操作;⽽StringBuilder未采⽤同步处理,属于线程不安全操 作
以上就是我们的全部内容了!!!!