问题:String、StringBuilder和StringBuffer的区别
String(JDK1.0) —— 不可变字符序列
StringBuffer(JDK1.0) —— 线程安全的可变字符序列
StringBuilder(JDK1.5) —— 非线程安全的可变字符序列
三者都用value[]存储字符序列。
但是String中的是常量(final)数组,只能被赋值一次。
讨论三者可不可变。本质上是指对象中的value[]字符数组可不可变,而不是对象引用可不可变。
理解三者关系的关键:
1. "+"操作的含义
1.1 字符串型 : "a"、"a" + "b"
可以在编译期间确定值的字符串,本质上是指向常量池中的字面量相等的字符串常量
这种类型字符串保存的是字符串常量的地址
1.2 字符串 + 对象 / 对象 + 对象型 : "a" + new String("b"); 、a + new String("b") 、 a + b
会拆分为3个步骤:
1.2.1 StringBuilder tmp = new StringBuilder(a);
1.2.2 tmp.append(b);
1.2.3 return tmp.toString();
这种类型的操作会生成一个新的String对象,导致对象内存地址变更,指向的是堆中String对象的地址
2. intern()的含义
intern字符串对象 == 拘留字符串对象,存在于堆中,其值等于常量池中某个字符串常量
当调用intern()时,如果常量池中已经有了该字符串的值,则直接返回该常量的地址。
如果没有则把该字符串的值加入常量池,并在堆中新建唯一的一个拘留字符串对象
调用intern()得到的结果是永远是常量池中该字符串常量的地址
3. ==比较的是字符串的地址,equals比较的是字符串的字面量
public class TestString {
public static void main(String[] args) {
String s1, s2, s3;
//字符串常量,"ab" 和"abc"为相同类型
s1 = "abc";
//字符串对象,new String(s1)、new String(s1) + ""同类型
s2 = new String(s1);
//拘留字符串,获取的是对应字符串的常量地址
// new String(s1).intern();和new String("abc").intern();同类型
s3 = new String(s1).intern();
System.out.println("常量 == 对象 " + (s1 == s2));
System.out.println("常量 == intern() " + (s1 == s3));
System.out.println("对象 == intern() " + (s2 == s3));
}
}