目录
2.3.2 大小写转换 toUpperCase() toLowerCase()
1.String原理介绍
1.1字符串构造
public static void main(String[] args) {
// 使⽤字符串常量进⾏赋值
String s1 = "hello";
System.out.println(s1);
// 直接new String对象
String s2 = new String("hello");
System.out.println(s1);
// 使⽤字符数组进⾏构造
char[] array = {'h','e','l','l','o'};
String s3 = new String(array);
System.out.println(s1);
//使⽤字节数组 构造对象
byte[] bytes = {11,12,13};
String s4 = new String(bytes);
System.out.println(str);
}
查看String源码,我们观察到:String是引用类型,内部并不存储字符串本身。
1.2字符串常量池
想要了解字符串的布局,我们首先得了解⼀个新的内存叫做:字符串常量池(StringTable),字符串常量池在JVM中是StringTable类,实际是⼀个固定大小的HashTable(不同JDK版本下字符串常量池的位置以及默认大小不同)"池"是编程中的⼀种常见的,重要的提升效率的方式。
1.3字符串内存存储
我们先看一个简单的字符串比较:
str1和str2都等于“123”,那么他们的存储过程是什么样的呢
第一步str1存储“123”时,会先将“123”存储到字符串常量池里
第二步当str2存储“123”时会先在字符串常量池中查找是否存在“123”,如果有则不会重复存储
那么如果我们new两个对象并给他们同样的值结果会和上面一样吗?
我们用==进行验证显然他们的地址是不一样的,那么他们又是如何存储的呢?
str3存储“123”时,会先将“123”存储到字符串常量池里,每次new都会在堆中实例化新的对象,对象创建成功需要调用常量池中的“123”,因此str3的地址实际上是new出来的对象的地址,同理,str4也会在堆中实例化一个新的对象,由于常量池中已经存在“123”,因此调用常量池中的“123”存储到new的对象当中,所以此时str3和str4d的地址分别是他们自己new的对象的地址。
2.常用方法介绍
2.1String对象的比较
我们在上面的代码中对两个字符串进行了比较,那么我们就详细讲解一下两种比较的不同之处
2.1.1==比较是否引用同一个对象
注意:对于内置类型,==比较的是变量中的值;对于引用类型==比较的是引用中的地址。
我们可以发现str1和str2引用的是同一个对象因此返回true,而str1和str3以及str3和str4引用的不是同一个对象因此全部返回false.
2.1.2 equals 方法:按照字典序比较
字典序:字符大小的顺序
String类重写了父类Object中equals方法,Object中equals默认按照==比较,String重写equals方法 后,按照如下规则进行比较,比如: s1.equals(s2)
虽然str1与str3引用的不是同一个对象,但是两个对象中放置的内容相同,因此输出true,str3和str4同理
2.1.3 compareTo 方法
按照字典序进行比较,与equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型。具体比较方式:
1. 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值
2. 如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值
2.1.4 compareToIgnoreCase 方法
与compareTo方式相同,但是忽略大小写比较
2.2字符串查找
字符串查找也是字符串中非常常见的操作,String类提供的常用查找的方法:
2.3转换
2.3.1 数值和字符串转化 valueOf()
2.3.2 大小写转换 toUpperCase() toLowerCase()
2.3.3 字符串转数组 toCharArray()
2.3.4 格式化
2.4字符串替换
replace()和replaceAll()效果一样
注意事项:由于字符串是不可变对象,替换不修改当前字符串,而是产生⼀个新的字符串.
2.5 字符串拆分
实现字符串的拆分处理(按空格拆分)
字符串的部分拆分
拆分是特别常用的操作.⼀定要重点掌握.另外有些特殊字符作为分割符可能无法正确切分,需要加上转义.
注意事项:
1. 字符"|","*","+"都得加上转义字符,前面加上 "\\" .
同理上述示例的点号
2. 而如果是 "\" ,那么就得写成 "\\\\" .
• 正则表达式需要\\ 来匹配⼀个反斜杠。
• 在Java字符串中表示\\ ,我们需要\\\\ 。
3. 如果⼀个字符串中有多个分隔符,可以用"|"作为连字符.
• | 在正则表达式中表示"或",意味着匹配它左边或右边的表达式。
多次拆分
2.6 字符串截取
注意事项:
1. 索引从0开始
2. 注意前闭后开区间的写法,substring(0,5)表示包含0号下标的字符,不包含5号下标
2.7 去除左右两边的空格
3.字符串的不可变性
String是⼀种不可变对象.字符串中的内容是不可改变。字符串不可被修改,是因为:
1. String类在设计时就是不可改变的,String类实现描述中已经说明了2. 所有涉及到可能修改字符串内容的操作都是创建⼀个新对象,改变的是新对象
3. String之所以不可以被修改的原因是内部数组因为为私有成员
4.字符串修改
对于String类本身来说,是不可以修改的,如果想要实现字符串的“修改”,需要:
但是实际上 hello并没有改变,而是新创建了一个String对象,对于String的拼接来说,如果是在循环当中会产生很多的临时对象。此时Java提供了StringBuffer和StringBuilder
可以看到在对String类进行拼接时,效率是非常慢,因此:尽量避免对String的直接需要,如果要修改建议尽量使用StringBuffer或者StringBuilder。
5. StringBuilder和StringBuffer
5.1 StringBuilder的介绍
String和StringBuilder最大的区别在于String的内容无法修改,而StringBuilder的内容可以修改。频繁修改字符串的情况考虑使用StringBuilder。
注意:String和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:
• String变为StringBuilder:利用StringBuilder的构造方法或append()方法
• StringBuilder变为String:调用toString()方法。
5.2 StringBuffer的介绍
StringBuffer和StringBuilder从方法的功能上来说没有太大区别,唯⼀的区别在于方法的声明上会存在⼀下区别:
StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作
如果想详细了解可以看官方文档 :
StringBuilder (Java SE 17 & JDK 17)declaration: module: java.base, package: java.lang, class: StringBuilderhttps://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/StringBuilder.html https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/StringBuffer.html
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/StringBuffer.html