String类
基本知识
String类的构造方法
String类的构造方法有很多,我们需要掌握常见的构造方法,来赋初识值。
1、new一个String类的对象
String name = new String("张三");
2、使用字符串常量进行赋值
String name = "张三";
相当于第一点的简化版
3、使用字符数组
char[] array = {'l','i','s','i'};
String name = new String(array);
System.out.println(name);//输出:lisi
4、使用字节数组
byte[] array = new byte[]{97,98,99,100,101};
String name = new String(array);
System.out.println(name);//输出:abcde
97 ~ 122 : a ~ z
65 ~ 90 : A ~ Z
48 ~ 57 : 0 ~ 9
字符串常量池
用于存储字符串常量值。当代码中使用双引号定义一个字符串时,Java 首先会检查字符串常量池中是否已经存在相同内容的字符串。如果存在,则直接返回该字符串的引用;如果不存在,则在常量池中创建一个新的字符串对象,并返回其引用。
String name1 = "abc";
String name2 = "abc";
System.out.println(name1 == name2);//输出:true
naem1 和 name2 都是通过双引号直接定义的字符串常量,它们指向字符串常量池中的同一个对象,因此使用 == 比较时返回 true。
在之前这个这样的代码:
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(str1 == str2);//输出false
str1 和 str2 是通过 new 关键字创建的字符串对象,它会在堆内存中创建一个新的对象,而不是从常量池中获取,所以 str1 和 str2 指向不同的对象,== 比较结果为 false。
常用方法
字符串比较
1、==比较
public static void test1() {
String str1 = "abc";
String str2 = "abc";
System.out.println(str1 == str2);//输出;true
}
图片如下:
public static void test2() {
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(str1 == str2);//输出;false
}
图片如下:(可以这么理解,但可能会存在一些问题)
2、equals()方法比较
3、compareTo()方法比较
这些之前都有提及过,这里不再说明。
4、compareToIgnoreCase()方法比较
调用方式和compareTo()一样,但这个比较忽略大小写。
String str1 = "abcd";
String str2 = "AbcD";
System.out.println(str1.compareToIgnoreCase(str2));//输出:0(表示忽略大小写相同)
求字符串长度
length()
public static void test1() {
String str1 = "abc";
System.out.println(str1.length());//输出:3
}
字符查找
charAt(int index)
返回index下标位置上的字符(方法会将字符串转换为字符数组),如果越界就会报错(StringIndexOutOfBoundsException)
String str1 = "abcd";
char ch = str1.charAt(3);
System.out.println(ch);//输出:d
indexOf()
indexOf(int ch)
返回ch第一次出现的位置,没有返回-1;
String str1 = "abcdefabcdabc";
System.out.println(str1.indexOf('b'));//输出:1
在类中存在重载的方法。
indexOf(int ch,int fromIndex)
从fromIndex下标开始找,返回ch第一次出现的位置,没有返回-1;
String str1 = "abcdefabcdabc";
System.out.println(str1.indexOf('b',5));//输出:7
indexOf(String str)
返回str第一次出现的首字符的位置,没有返回-1;
String str1 = "abcdefabcdabc";
System.out.println(str1.indexOf("fa"));
indexOf(String str,int fromIndex)
从fromIndex下标开始找,返回str第一次出现的首字符的位置,没有返回-1;
String str1 = "abcdefabcdabc";
System.out.println(str1.indexOf("fa"),7);//输出:-1
lastIndexOf()
lastIndexOf(int ch)
从后面开始查找,返回ch第一次出现的位置,没有返回-1;
String str1 = "abcdefabcdabc";
System.out.println(str1.lastIndexOf('b'));//输出:11
lastIndexOf(int ch,int fromIndex)
从fromIndex下标开始找,从后面开始查找,返回ch第一次出现的位置,没有返回-1;
String str1 = "abcdefabcdabc";
System.out.println(str1.lastIndexOf('b'),6);//输出:1
lastIndexOf(String str)
从后面开始查找,返回str第一次出现的首字符的位置,没有返回-1;
String str1 = "abcdefabcdabcfa";
System.out.println(str1.lastIndexOf("fa"));//输出:13
lastIndexOf(String str,int fromIndex)
从fromIndex下标开始找,从后面开始查找,返回str第一次出现的首字符的位置,没有返回-1;
String str1 = "abcdefabcdabc";
System.out.println(str1.lastIndexOf("fa",7));//输出:5
转换
数值和字符串转换
在数据类型的字符串类型中有所讲到。
这里只补充一个
System.out.println(String.valueOf(new Student("lisi", 18)));
这里会调用Student类重写的toString()方法。
大小写转换
toLowerCase()方法和toUpperCase()方法
public static void main(String[] args) {
String name = "WorD";
System.out.println(name.toLowerCase());
System.out.println(name);
System.out.println(name.toUpperCase());
System.out.println(name);
}
输出:
word
WorD
WORD
WorD
字符串转字符数组
toCharArray()方法
public static void test2() {
String name = "zhangsan";
//字符串转字符数组
char[] chars = name.toCharArray();
for (char ch:chars) {
System.out.print(ch);
}
System.out.println();
//字符数组转字符串
String str = new String(chars);
System.out.println(str);
}
格式化输出
String.format()方法
public static void test3() {
String date = String.format("%d/%d/%d",2025,3,24);
System.out.println(date);
}
字符串替换
replace()方法、replaceAll()方法、replaceFirst()方法。
public static void test4() {
String name = "张三丰";
System.out.println(name.replace('张', '李'));//可串字符
System.out.println(name.replace("张三", "李四"));//可串字符串
String str = "ab_cd_ab";
System.out.println(str.replaceAll("ab", "hahaha"));//替换所有匹配的字符串
System.out.println(str.replaceFirst("ab", "hahaha"));//替换第一个匹配成功的字符串
}
字符串拆分
split()方法
public static void test5() {
String str = "Hello word Java";
String[] string = str.split(" ");
for (String s:string) {
System.out.println(s);
}
System.out.println("---------");
String[] string1 = str.split(" ",10);//最多拆分成10组
for (String s:string1) {
System.out.println(s);
}
System.out.println("---------");
String[] string2 = str.split(" ",2);//最多拆分成2组
for (String s:string2) {
System.out.println(s);
}
}
输出:
Hello
word
Java
---------
Hello
word
Java
---------
Hello
word Java
注意:
当拆分的节点为特殊字符时,需要用\
进行转义。
eg.
1、|
*
+
,在前面加上\\
public static void test6() {
String str = "1 + 3 = 2 + 2";
String[] string = str.split("\\+");
for (String s:string) {
System.out.println(s);
}
}
2、\
,需要用\\\
进行转义。
public static void test7() {
String str = "2025\\3\\24";
String[] string = str.split("\\\\");
for (String s:string) {
System.out.println(s);
}
}
3、如果⼀个字符串中有多个分隔符,可以用|
作为连字符
public static void test7() {
String str = "2025\\3\\24+2025";
String[] string = str.split("\\\\|\\+");
for (String s:string) {
System.out.println(s);
}
}
字符串截取
substring()方法
public static void test8() {
String name = "zhangsan";
System.out.println(name.substring(5));
System.out.println(name.substring(5,8));//返回 String,生成一个新的字符串对象
System.out.println(name.subSequence(5,8));//返回CharSequence接口类型,没有生成一个新的字符串对象
}
注意:这里下标写8没有报错,说明截取范围为[5,8)。
去掉首尾空格
trim()方法
public static void test9() {
String name = " zhang san ";
System.out.println(name.trim());
}
输出:
zhang san
intern()方法
intern()的作用是:将字符串放入字符串常量池 或者 返回该池中已有的相同字符串引用。
1、如果存在相同内容的字符串,intern() 方法会返回该字符串的引用。
2、如果字符串常量池中不存在相同内容的字符串,JVM 会将这个字符串加入池中,并返回该字符串的引用。
public static void test3() {
char[] ch = new char[]{'a', 'b', 'c'};
String s1 = new String(ch);
String s2 = "abc";
System.out.println(s1 == s2);
}
输出:
false
public static void test3() {
char[] ch = new char[]{'a', 'b', 'c'};
String s1 = new String(ch);
s1.intern();
String s2 = "abc";
System.out.println(s1 == s2);
}
输出:
true
public static void test3() {
String s2 = "abc";
char[] ch = new char[]{'a', 'b', 'c'};
String s1 = new String(ch);
s1.intern();
System.out.println(s1 == s2);
}
当将顺序调换时,输出结果发生变化,输出false。
为什么呢?
调用 intern() 时,发现字符串常量池已存在 “abc”,不会修改常量池(不做任何操作)。此时 s1 仍指向堆中的对象,而 s2 指向常量池中的对象。
字符串不可变性
String是一种不可变的对象,字符串中的内容是不可改变。
所以当对字符串内容进行修改的操作都是创建了一个新的对象,改变的就是这个新的对象。
字符串修改
代码分析
public static void test4() {
String name = "zhang";
name = "zhang" + "san";
System.out.println(name);
}
对于"zhang" + "san"这一步来说,相当于创建了一个新的对象。并没有直接对字符串"zhang"进行修改。当new的对象多了,会造成运行效率降低。为了解决这一问题,提供了StringBuffer
和StringBuilder
public static void test6() {
String str1 = "+";
for (int i = 0; i < 100; i++) {
str1 +="+";//new了100次新对象
}
System.out.println(str1);
//StringBuffer str2 = "+";//不支持这样直接赋值;
StringBuffer str2 = new StringBuffer("+");
for (int i = 0; i < 100; i++) {
str2.append("+");
}
System.out.println(str2);
//StringBuffer str2 = "+";//不支持这样直接赋值;
StringBuilder str3 = new StringBuilder("+");
for (int i = 0; i < 100; i++) {
str3.append("+");
}
System.out.println(str3);
}
注意:
1、 对于StringBuffer和StringBuilder是不支持直接用字符串赋值的
StringBuffer str2 = "+";//不支持这样直接赋值;
StringBuilder str3 = "+";//不支持这样直接赋值;
2、对于append()就是将参数的字符串表示附加到此序列。
3、这时候就会问了:StringBuffer和StringBuilder的append方法不是一样的吗?
我们分别查看其的方法。
发现StringBuffer中多了修饰符synchronized。具体表示什么意思之后再提及。
4、我们还发现了再append方法中都返回的是this,说明此修改字符串并没有创建新的对象。
StringBuffer类和StringBuilder类中的内置方法
对于具体的内容可以通过帮助文档、AI等来查找。
append()
public static void test7() {
StringBuffer str1 = new StringBuffer("hello");
str1.append(" word!");
System.out.println(str1);
str1.append(2025);
System.out.println(str1);
}
输出:
hello word!
hello word!2025
deleteCharAt(int index)
删除index位置字符
public static void test8() {
StringBuffer str1 = new StringBuffer("hello");
System.out.println(str1.deleteCharAt(1));
}
输出:hllo
delete(int start,int end)
删除[start,end)区间内字符
public static void test9() {
StringBuffer str1 = new StringBuffer("hello");
System.out.println(str1.delete(0,1));//删除[0,1)
}
输出:ello
reverse()
反转字符串
public static void test10() {
StringBuffer str1 = new StringBuffer("hello");
System.out.println(str1.reverse());
}
输出:olleh