Java字符串相关知识
2023/5/9大约 3 分钟
字符串
Java里面字符串分为String ,StringBuilder和StringBuffer
三种字符串类的区别
- 三者共同之处都是final类,不允许被继承
String是一个长度不可变的字符序列,底层是一个被final修饰的char[]数组
StringBuffer是线程安全的可变字符串序列,效率低,底层是char[]数组存储
StringBuilder是非线程安全的可变字符串序列,效率高,底层是chart[]数组存储- 运行速度:因为StringBuilder是线程不安全的,所有的公开方法没有加锁的,但是StringBuffer是线程安全的,所有的公开方法都是同步的(synchronized)的,所以StringBuilder的速度要大于StringBuffer,而String是最慢的,因为需要不断地开辟空间,而StringBuilder和StringBuffer则是直接对该对象进行更改的。
- 线程安全问题:StringBuilder线程不安全,StringBuffer线程安全
- 总结: String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况
String拼接方式
当我们执行 “str += " World";”时底层其实走四步:
先创建一个StringBuilder对象,并调用无参数的构造方法。
StringBuilder对象调用append方法,把str内部 “Hello” 拼接到内部。
StringBuilder对象再次调用append方法,把 " World" 拼接到内部。
最后StringBuilder对象调用toString方法,把拼接好的字符串传给str。
所以String拼接会创建StringBuilder对象,这样的效率是低下的如果在大量拼接的场景下
String内存模型
一般分为编译期和运行期,如果能够在编译期读取的字符串字面值会直接指向字符串常量池地址
运行期进行拼接会调用StringBuilder创建StringBuilder对象,然后toString方法生成一个新的String对象。
首先来个代码:
public class test2 {
public static void main(String[] args) {
String a=new String("1")+new String("1");
a.intern();
String b="11";
System.out.println(a==b);
}
}这里的结果会输出true,我们会在字符串常量池中创建“1”,然后Heap中生成了a的对象,但此时常量池中是没有"11"的,此时我们再使用a.intern,如果在jdk7以前我们会在常量池中创建"11"这个对象,而jdk7以后,常量池不需要再储存一份对象了,而是直接引用a的对象,b直接会去常量池创建,但此时发现有了"11"的引用,所以b会指向堆中的a
String s1 = new String("1") + new String("1");//s1变量记录的地址为:new String
s1.intern();//在字符串常量池中生成"11"。如何理解:jdk6:创建了一个新的对象"11",也就有新的地址;jdk7:此时常量池中并没有创建"11",而是创建了一个指向堆空间中new String("11")的地址;
String s2 = "11";
System.out.println(s1 == s2);//jdk6:false;jdk7:true
一篇不错的String文章:https://www.cnblogs.com/r1-12king/p/15946648.html
JDK7过后常量池就在Heap中了

