参考网页
https://blog.csdn.net/isscollege/article/details/78398968
https://www.jianshu.com/p/9819eb48716a
疑问
String是final类,也就是不可变的。
String a = “abc”;
a = “xxx”;
实际上内存中“abc”、“xxx”都没变(每次赋值实际上都开辟了新的一块内存)。只是a的引用变了。
那么有个新的疑问,如下代码
String a = “abc”;
a = “abcde”;
可以看到“abcde”内容里包含“abc”,那么“abc”会不会被复用呢?就是“abcde”、“abc”起始地址会不会一样呢,如下图这样:“abcde”取的是5个char,“abc”取的是3个char,前三个char“abc”是一样的?
需要实际测试一下。
试验
JDK版本
C:\Users\lenovo>java -version
java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)
测试代码
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class StringAddressTest {
static final Unsafe unsafe = getUnsafe();
static final boolean is64bit = true;
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InterruptedException {
String a = "abc";
String b = "abc";
String c = "abcde";
String d = "abcdefghigklmnopq";
System.out.println(a == b);
// System.out.println("======hashCode======");
// System.out.println(a.getClass() + "@" + a.hashCode());
// System.out.println(b.getClass() + "@" + b.hashCode());
// System.out.println(c.getClass() + "@" + c.hashCode());
// System.out.println(c.getClass() + "@" + d.hashCode());
//
// System.out.println("======System.identityHashCode======");
// System.out.println("a@" + System.identityHashCode(a) );
// System.out.println("b@" + System.identityHashCode(b) );
// System.out.println("c@" + System.identityHashCode(c) );
// System.out.println("d@" + System.identityHashCode(d) );
System.out.println("======Addresses======");
printAddresses("a:", a);
printAddresses("b:", b);
printAddresses("c:", c);
printAddresses("d:", d);
// TimeUnit.SECONDS.sleep(10000);
}
public static void printAddresses(String label, Object... objects) {
System.out.print(label + ": 0x");
long last = 0;
//获取偏移地址值
int offset = unsafe.arrayBaseOffset(objects.getClass());
//获取变量占用空间大小
int scale = unsafe.arrayIndexScale(objects.getClass());
switch (scale) {
case 4:
long factor = is64bit ? 8 : 1;
final long i1 = (unsafe.getInt(objects, offset) & 0xFFFFFFFFL) * factor;
System.out.print(Long.toHexString(i1));
last = i1;
for (int i = 1; i < objects.length; i++) {
final long i2 = (unsafe.getInt(objects, offset + i * 4) & 0xFFFFFFFFL) * factor;
if (i2 > last) System.out.print(", +" + Long.toHexString(i2 - last));
else System.out.print(", -" + Long.toHexString(last - i2));
last = i2;
}
break;
case 8:
throw new AssertionError("Not supported");
}
System.out.println();
}
private static Unsafe getUnsafe() {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
return (Unsafe) theUnsafe.get(null);
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
运行结果
true
======Addresses======
a:: 0x781eea450
b:: 0x781eea450
c:: 0x781eea480
d:: 0x781eea4b8
分析1
实际测试结果可见,
String a = "abc";
String b = "abc";
出现的是同样的结果
String c = "abcde";
String d = "abcdefghigklmnopq";
都是不同的结果了。
也就是说字符串没有被复用。
分析2
请注意JDK版本,是不是别的版本也是这样的结果?不知道。