Strings1=newString("aa")+newString("bb");s1.intern();Strings2="aabb";System.out.println(s1==s2);//true我已经了解,JDK6中intern()会在常量池中不存在的情况下直接拷贝值放入常量池,而JDK7是会把堆中的引用放入常量池。这段代码中的字面量"aa""bb""aabb"在编译器就已经放入常量池中了,很多文章都说成执行到Strings2="aabb"才把“aabb”放入常量池,我认为是不对的。所以在s1.intern()这个操作应该是没有产生任何副作用的,s1仍然指向堆中的一个对象,s2仍然指向常量池中的一个对象。但实际结果却为true,而且把Strings2="aabb"移动到s1.intern()前面,结果就是我所预期的false。到底是为什么呢?
2 回答
MMTTMM
TA贡献1869条经验 获得超4个赞
先说点别的:这里的字符串拼接没有被优化"xxx"这样的字面量声明自带intern不同版本的java效果各种不一样一般的用法是Stringx=x.intern(),因为可能会返回常量池里的引用intern属于用时间换空间,一般也很少用到…编译期没有字符串常量池,字符串常量池是运行期的东西,也就是说直到某个字符串字面量声明或者intern之前,这个字符串不会进入字符串常量池中再说你这个例子:如果s1.intern()发生在s2的声明之前,s1进常量池,s2的声明自带intern,从常量池里找到s1赋值给自己,于是和s1是同一个引用反过来,s2先声明,进常量池,s1需要计算,得到一个新的字符串,和s2就不是同一个了,这时候如果做s1.intern()==s2还是true
POPMUISE
TA贡献1765条经验 获得超5个赞
涉及到更深入的类加载机制原答案比较混乱,我整理一下就是:1.查看字节码文件中可以看到,定义一个字面量的Strings2="aabb"对象,其实是存储了2个内容,一个是UTF8aabb,一个是String对象指向这个UTF8,这个是重点,使用常量池中的数据,实际使用的是这个String对象。2.加载类的时候会读取字节码文件中Constantpool里的内容放入运行期常量池,但这个时候只创建了UTF8aabb这个对象(C中的Symbol类型),配套的String对象是懒加载的,只有当第一使用到这个常量的时候才会在常量池中去创建这个String对象。3.再结合问题中的代码,程序开始执行后,常量池中已经有"aa""bb""aabb"3个UTF8对象,但是并没有可用的String对象。当执行完第一行代码,会创建常量池中的"aa""bb"的String对象;当程序执行到s1.intern();时,常量池中并不存在"aabb"这个String对象,于是将s1的引用放入常量池作为String对象,后面代码再去常量池获取这个字面量的时候,返回的就是s1的地址,所以s1==s2。4.推测,上面这种情况,类加载时候创建的"aabb"Symbol对象就无用了,未证实。5.当先执行Strings2="aabb";的时候,会直接去常量池中获取对象,发现常量池中的String对象不存在,于是创建一个,指向常量池中的UTF8aabb对象。下一步再执行在s1.intern();的时候,发现常量池中已经存在,放不进去了,所以结果是s1指向堆中的一个对象,s2指向常量池中的一个对象,2者并不相等。
添加回答
举报
0/150
提交
取消