关于常量池中的String类型的数据,在JDK6中只可能是对象,在JDK7中既可以是对象也可以是引用
案例一:
String s1 = new String("1");
String s2 = "1";
System.out.println(s1 == s2);
s1: 执行new String("1"),JVM 首先在字符串常量池中查找或添加字面量"1",然后在堆内存中新建一个内容为"1"的String对象。s1指向的是这个堆对象。s2: 指向字符串常量池中已有的"1"。结果:s1 == s2比较的是引用地址,一个在堆中、一个在常量池中,因此结果为false。
案例二:
String s1 = new String("1") + new String("1");
String s2 = "11";
System.out.println(s1 == s2);
s1: 通过两个new String("1")创建两个堆中对象,然后使用StringBuilder进行拼接,最终生成了一个新的"11"字符串对象,存放在堆内存中。s2:"11"是字面量,编译器会将其放入字符串常量池,并由s2指向。结果:s1指向堆中的"11"对象,s2指向常量池中的"11",引用不同,结果为false。
案例三:
String s1 = new String("1") + new String("1");
String s2 = s1.intern();
System.out.println(s1 == s2);
s1: 与案例二一样,通过拼接在堆中创建了一个"11"的String对象。intern(): 在 JDK7+ 中,intern()会将当前堆中的对象引用尝试放入字符串常量池中。如果常量池中尚未存在"11",则将该对象引用添加进去,并返回这个引用。s2: 返回的是字符串常量池中的引用,而由于常量池中原本没有"11",此时存入的是s1指向的堆对象本身。结果:s1 == s2,两者引用相同,结果为true。
JVM冷启动时,String str = “1”
执行流程:
-
JVM 首先会去常量池中查找有没有字面量
"1":- 若没有,JVM 会在堆中创建一个字符串对象
"1",并将它的引用记录进常量池; - 若已存在,JVM 直接复用已有对象的引用。
- 若没有,JVM 会在堆中创建一个字符串对象
-
局部变量
str会从常量池中取出引用,指向对应的字符串对象。
所以即使没有显式地写
new,JVM 也可能创建对象,但前提是该字面量还未进入常量池。