一、String
1.1
String str1 = "123";
String str2 = "123";
System.out.println(str1 == str2); // true
System.out.println(str1 == "123"); // true
分析:字符串常量保存在堆中,同一常量值在内存中只有一份,栈中两个(引用)指针只指向同一地址。String 是引用类型,==比较的是内存地址。
1.2
String str1 = "123";
String str2 = new String("123");
System.out.println(str1 == str2); // false
System.out.println(str1.equals(str2)); // true
分析:new 在堆中申请了新的空间,因此两个常量的内存地址不同,==比较引用的地址。equals()比较两个内存中的值是否相等。
1.3
String str1 = "123";
str1 += "456"; // 修改、替换等也是
System.out.println(str1); // 123456,新的内存空间,新的对象
分析:String 的不可变性,是指堆中的值不可更改,但是指针(引用)str1可以更改,可以指向其他堆中的常量。+= 并不是在原有堆”123“追加”456“,而是申请了新的堆内存存储”123456“,str1指向这个新的堆内存。
1.4 Stirng 的底层是一个final 修饰的数组,不可变
private final byte[] value;
二、StringBuilder
2.1 可变,底层是一个可变数组,数组长度不足时自动扩容
byte[] value;
2.2 适用于单线程、操作修改频繁的场景,线程不安全
三、StringBuffer
3.1 可变,底层是一个可变数组,可自动扩容
byte[] value;
3.2 线程安全,可用于多线程场景,每个方法上都加了synchronized关键字
synchronized void getBytes(byte dst[], int dstBegin, byte coder) {
super.getBytes(dst, dstBegin, coder);
}