基本概述
String是典型的Immutable类,这个在 final、finally、finalize 区别 中有提到过,类被声明为final、属性被声明为final,由于其不可变的性质,拼接、截取等动作,都会产生新的String对象。
StringBuffer就是为了解决字符串拼接、截取造成的太多中间对象而提供的一个类,它是线程安全的可修改字符序列,但就是由于线程安全机制,导致额外的性能开销,所以该类只适合应用在有线程安全需要的场景。
StringBuilder局部中应用非常多,因为它具备StringBuffer的功能,唯一的不同点,它不是线程安全的。
深入理解
为什么String采用Immutable实现? 因为无法对它内部数据进行任何更改 ,首先 保证了基础线程安全(安全性),其次,不可变使得对象能被共享,不需要额外复制数据(复用性)。
StringBuffer 和 StringBuilder 都 继承了 AbstractStringBuilder ,基本方法都一样,唯一区别是StringBuffer简单粗暴的在方法中加上了synchronized进行修饰,底层利用可修改的char数组。
创建时,初始化字符串长度16,如果确定拼接会发生多次并且大概可预测,为了避免多次扩容带来的开销,可以提前设置,扩容是抛弃原来数组、创建新的数组、进行数组拷贝。
优化
在jdk8中,字符串的拼接操作,会自动被javac转化为StringBuilder操作,在jdk9中,为了更加统一字符串操作优化,提供了StringConcatFactory,作为一个统一的入口。但是jdk7的使用者,需要谨慎选择。
缓存分析
jdk6 提供intern(),提示jvm缓存字符串,创建字符串对象并调用,如果已经缓存过,只会返回缓存实例,但是被缓存的实例是存储在PermGen里,空间有限而且不会被fullgc照顾到,使用不当会导致oom。
在后续版本中,改缓存放置在堆中,避免了永久代占满的问题,默认缓存大小也不断的扩大,从最初1009到7u40以后被修改为60013。
jdk1.7之后,常量池被放到了堆空间中,使得intern()的实现原理也不同。
用例 1:
String god = new String("hel") + new String("lo");
System.out.println(god.intern() == god);
System.out.println(god == "hello");
返回结果 true 、 true
首先,第一行会在常量池存hel 和 lo
但是, String god = new String("hel") + new String("lo") 会在堆中生成字符串 hello , 而在常量池中没有
在jdk1.6之前god.intern()会将字符串复制到常量池中,jdk1.7之后,如常量池不存在,则在内存中找,如果内存中有,就在常量池中保存一个指向内存中对象的引用。所以第二段:god.intern() == god , 返回true
用例 2:
String tmp = "hello";
String god = new String("hel") + new String("lo");
System.out.println(god.intern() == god);
System.out.println(god == "hello");
返回 false、false
首先,第一段,已经将hello存放到常量池中
第二段 god 为内存中引用
god.intern() , 因为常量池中存在,所以返回的是常量池中的引用而非内存对象中的引用,所以god.intern() == god 为false
god 是对象引用 , “hello” 是常量池中引用,所以 也为false
用例 3:
String mysq = "aa" + "bb" + "cc";
String m = "aabbcc";
System.out.println(mysq == m);
System.out.println(m.intern() == mysq);
返回 true 、 true
可见 mysq本身是常量池中引用来
用例 4:
String mysq = "aa" + "bb" + "cc";
String m = new String("aabbcc");
System.out.println(mysq == m);
System.out.println(m.intern() == mysq);
返回 false 、 true
题外话
前边提到,字符串存储结构使用char数组进行,但是char是两个bytes大小,导致编程语言的非密度性。jdk9中,字符串底层从char改变为byte数组,期望于更小的内存占用,更快的操作速度。