public class Demo1 {
public static void main(String[] args) {
String s = new String("111");
s.intern();
String s1 = "111";
System.out.println(s == s1); //jdk6 : false jdk7/8 : false
}
}
字节码文件 :

1-5 : 创建一个string对象, 并把这个string对象的值存储到常量池中(ldc指令)
6 : 调用string的intern方法, 将字符串存储到常量池中, 如果字符串常量池中存在该变量, 则返回字符串常量池中的地址
无论是jdk6 或者是jdk7/8 s=s1 比较的都是堆空间的地址和常量池中的地址, 所以全是false
2.
public class Demo1 {
public static void main(String[] args) {
String s = new String("111") + new String("222");
s.intern();
String s1 = "111222";
System.out.println(s == s1); //jdk6 : false jdk7/8 : true
}
}
字节码 :

1. 首先讨论
String s = new String("111") + new String("222"); 创建了多少对象对象1 : new StringBuilder();
对象2 : new String("111");
对象3 : 字符串常量池中的"111"
对象4 : new String("222")
对象5 : 字符串常量池中的"222"
对象6 : StringBuilder.toString()方法创建的字符串对象
注意 : StringBuilder.toString()创建的string对象不会同步到字符串常量池中
new String(); 创建的对象会同步到字符串常量池中
结果讨论 :
在jdk6中 , 方法区的实现是永久代, 字符串常量池存放在永久代中, 因此
String s = new String("111") + new String("222")和 String s1 = "111222" 比较的仍然是堆空间和常量池中的两个不同地址在jdk7/8之后, 方法区的实现是原空间, 并且将字符串常量池存放到堆空间 , 当定义一个字符串对象时 , 如果堆中存在该对象, 那么在常量池中存放的就是堆空间中的地址, 因此结果为true
本文探讨了Java中字符串常量池在JDK6和7/8版本中的行为差异:在JDK6中,堆空间和常量池地址不一致导致`s == s1`比较为false;而在JDK7/8中,字符串常量池移至堆内存,相同字符串会指向同一地址,`s == s1`在新版本下可能为true。


606

被折叠的 条评论
为什么被折叠?



