java的String(详述)
文章目录
一、何为String?
在学习C语言中,就已经涉及到了字符串的概念,但是在C语言中并没有字符串的类型,只能通过字符数组和字符指针的概念达到字符串的效果。

但是中java里面专门提供了字符串类型:String,在C语言中没有字符串类型这样的说法。String属于引用型数据类型。
二、字符串的构造
String类型的构造方法有很多,常用的有以下三种:
1、使用常量串构造
public static void main(String[] args) {
String s = "abcdef";
System.out.println(s);
}
2、直接new String对象
public static void main(String[] args) {
String s = new String("abcdef");
System.out.println(s);
}
3、使用字符数组进行构造
public static void main(String[] args) {
char[] ch = {'a' , 'b' , 'c' , 'd' , 'e' , 'f'};
String s = new String(ch);
System.out.println(s);
}
一般来说使用字符串常量构造是最常用的,但实际上字符串常量构造的本质就是new String,所以前两个方法本质上是一样的,只是使用字符串常量构造会比较迅速。
public static void main(String[] args) {
int[] array1 = {1,2,3,4};
int[] array2 = new int[]{1,2,3,4};
}
和数组构造方法一样,两者没有区别,只是使用直接构造会比较迅速。
三、字符串的本质
String是引用行数据类型,本身并不存储字符串,String类型的引用只用于存储对象的地址,以及调用相应的方法进行对对象的操作。
在String的底层有一个Value数组,用于存储字符串,也就是说虽然Java定义了字符串类型,但本质是还是用数组进行存储字符串的,和C语言构造字符串有些类似,区别在于Java对该数组进行了封装,在字符串类型String的表面并看不出来从而达到了字符串类型的实现。

在JDK1.8中,String的底层Value数组是char类型的,但是在JDk17中,Sting的底层Value数组是byte类型的。但两者并没有太大的区别,字符本质上就是数字,可以理解为String类当中的任何方法,都是对value数组进行操作的。

引用型数据类型String的存储空间如图:
public static void main(String[] args) {
String s1 = "abc";
String s2 = "aaa";
String s3 = s1;
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
}

所以说String本身并不存储字符串,而是存储String对象的地址。
三、String常用的方法
1、String对象的比较
1.1、String对象的比较:equals()
对于基本数据类型来说,两者之间的比较可以直接用“==”进行比较

但是对于引用行数据类型来说使用“ ==”进行比较并不合适,如图:s1和s2同样是“abc”,但比较结果确是不等于。

对于基本数据类型来说:“= =”比较的是变量中的值
对于引用型数据类型来说:“= = ”比较的是两个引用中存储的地址。
这个时候我们就需要相应的方法进行比较String对象底层真正存储字符串的数组value,boolean equals(Object object)方法,按照字符大小的顺序进行比较

String类中重写了Object中的equals方法,Object中的equals方法默认安装= =进行比较,但是在引用行数据类型并不适用,String重写equals方法后,按照字符大小的顺序进行一一比较。也就是真正的比较String类底层的value数组,而并非比较引用中的地址。
需要注意的是:引用不能指向引用,一个引用只能指向一个对象。
String s1 = new String("abc");
String s2 = new String("abc");
String s3 = s1;
"s3 = s1"的意思并不是引用s3 指向 引用s1,而是引用s3指向了引用s1指向的对象。
1.2、忽略大小写的String对象的比较:equalsIgnoreCase(String s)
在我们的生活中经常需要验证码进行登陆某某软件,我们可以发现验证码中输入过程中是忽略大小写的,只要是字母相同,大写小写都可以,String类当中当然也定义了忽略大小写比较的方法。

1.3、比较String对象的大小:compareTo(String s)
与equals方法不同的是,equals返回的是boolean类型,compareTo方法返回的是int型的。具体比较方式:
1、先按照字符大小的顺序进行比较,如果出现不相等字符,直接返回两者之间的差值
2、如果两个字符串之间的长短不同,在比较过程中短的字符串先比较完了并且完全相同,此时返回字符串长度的差值。

在使用compareTo()方法时,需要注意调用的顺序,顺序不同输出的差值不同
1.4、忽略大小写的String对象比较:compareToIgnoreCase(String s)
和compareTo方法的使用方式一样,但是忽略大小写,同时有需要注意调用的顺序,并且该方法只能忽略字符,如果遇到中文会直接跳过。

2、字符串查找

public static void main(String[] args) {
String s = "aaabbbcccaaabbbccc";
System.out.println(s.charAt(3)); //'b
System.out.println(s.indexOf('c')); //6
System.out.println(s.indexOf('c',10)); //15
System.out.println(s.indexOf("bbb")); //3
System.out.println(s.indexOf("bbb",10)); //12
System.out.println(s.lastIndexOf('c')); //17
System.out.println(s.lastIndexOf('c',10)); //8
System.out.println(s.lastIndexOf("bbb")); //12
System.out.println(s.lastIndexOf("bbb",10)); //3
}
3、字符串转化
3.1、数值和字符串之间的转化valueOf()
String.valueOf( X ),X可以是对象、int、boolean、double等数据类型,最终会返回对应的字符串。

String.valueOf()方法在底层调用了toString方法,在类中重写的toString方法,重写toString方法可以按照自己的想法输出内容,并且仔细观察可以发现,在println()方法中也调用了String.valueOf()方法

如果在类中没有重写toString方法,那么println()方法只能默认输出引用所存储的地址。
3.2、大小写的转化:toUpperCase(), toLowerCase()
可以直接同过String的引用调用toUpperCase()方法和toLowerCase()方法,需要接收String类的返回值,String的方法都是返回一个new的String对象,不在原字符串上修改
public static void main(String[] args) {
String s = "AbcDef";
String s1 = s.toLowerCase();//输出abcdef
String s2 = s.toUpperCase();//输出ABCDEF
}
3.3、字符串转数组:toCharArray()
toCharArray()方法可以将字符串挨个转换成数组,需要用char类型的数组进行接收
public static void main(String[] args) {
String s = "AbcDef";
char[] ch = s.toCharArray();
}
同时如果char类型的数组想转换为字符串,只需要将数组传给String的构造方法即可
public static void main(String[] args) {
String s = "AbcDef";
char[] ch = s.toCharArray();
String str = new String(ch);
}
3.4、字符串格式化format()
简而言之就是将内容通过自己规定的格式输出为字符串
public static void main(String[] args) {
String str = String.format("%d-%d-%d" , 2024,10,22);//str == 2024-10-22
}
需要注意的是format()方法的参数列表由第一个输入值决定,第一个输入值里面有多少个占位符,后面就要补充多少个数据,前后需要呼应。
4、字符串替换
4.1、替换所以指定的内容:replace()方法,replceAll()方法
两个方法基本一致,但是不同的是replace()方法构有重载,可以替换字符或者字符串,但是replaceAll()方法只能替换字符串

String str = "abcde";
String s1 = str.replace("abc" , "aaa"); //aaade
String s2 = str.replace('a' , 'b'); //bbcde
String s3 = str.replaceAll("abc" , "aaa");//aaade
}
4.2、替换首个内容:replaceFirst()
替换调用者里面的首个内容,剩下的不变,并且将替换后的内容以new String的方式返回,需要用String类进行接收
public static void main(String[] args) {
String str = "abcabcabc";
String s1 = str.replaceFirst("abc","aaa");//aaaabcabc
}
需要注意的是:由于字符串是不可变对象,替换不修改当前的字符串,而是产生新的字符串
5、字符串拆分
split()方法可以将完整的字符串按照指定的分隔符拆分才若干个子字符串。

split()方法也构成了重载,一个是不规定分割成多少个子字符串,一个是规定分割成limit个字符串
public static void main(String[] args) {
String str = "abc abc abc abc";
String[] s1 = str.split(" "); //abc abc abc abc,分割成4个
String[] s2 = str.split(" " , 2); //abc abc abc abc,分割成0个
}
但是比较需要注意的是,有一些特殊字符作为分隔符的时候可能无法正常分割,需要加上转义,比如拆分ip地址。

split()方法没有正常运行,JDk无法识别“.”,因为“.”默认是一个操作符,用于调用类里面的方法或者变量,所以这个时候需要转义才可以使split()方法正常分割,需要在“.”前面加上“\”即可。

1、字符“|”,“*”,“+”都需要加上转义字符,前面加上“\”
2、如果是“\”字符,那么需要写成“\\”,因为“\”需要加上一个“\”转义才是真正的“\”的意思,那也就是说,在字符串里面需要用“\”的话就写成“\”,那么split()方法里面想要使用“\”作为分隔符,则方法里面想要写成“\\”
3、如果一个字符串中有多个分隔符,可以用“|”作为连字符

6、字符串截取
从一个完整的字符串中截取部分内容,可以使用String.substring()方法。

substring()方法也构成了重载,当参数列表只有一个时,表示截取该位置到字符串结尾的内容,如果参数列表有两个,表示截取范围内内容。并且是左闭右开,也就是第二个参数只能取到该位置的前一个内容,无法取到该位置上的内容
public static void main(String[] args) {
String str = "abcdef";
String s1 = str.substring(3);//def
String s = str.substring(2 , 5);//cde
}
需要注意的是,
1、索引是从0开始
2、注意前闭后开区间的写法,substring(0,5)表示保护0号下标的字符,但不包含5号下标的字符
7、去掉左右空格,保留中间空格
trim()方法可以去掉字符串开头和结尾的空白字符,比如制表符,空格,换行等

四、String的注意事项
String是一种不可变对象,字符串中的内容是不可变的,一旦初始化完成后就无法改变了,虽然可以使用“+=”进行字符串追加,但是并不是真正意义上的追加,“+=”实际上是new了几个新对象进行追加成为一个新的对象最后再返回变成String类型,本质意义上也不是在原字符串的基础上追加
并且String类被final修饰,表示String类型不可以被继承
String类的字符实际是保存在内部维护的value字符数组中,并且该数组也被final修饰,表示value本身的引用对象不可以修改,即不可以引用其他的字符数组,但是value引用的数组内容是可以修改的
所有涉及到字符串内容修改的方法,都是创建一个新对象,改变的是新对象,而并非原对象,最终返回新对象
更多推荐



所有评论(0)