2017/9/12 String.intern()

参考:

《深入理解java虚拟机》 p56-57  

揭开 String.intern() 那神秘的面纱

深入分析String.intern和String常量的实现原理

1.  new String("abc")创建了几个对象??

记住。这个与JDK版本无关。

如果常量池原来有个“abc”,那么只创建一个对象;

如果常量池中原来没有字符串"abc",那么就会创建两个对象。

2. String.intern()方法(Native方法) 1.6复制的是实例 1.7复制的是引用

jdk1.6时:如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。(常量池分配在永久代)

JDK1.7时:Java 7将常量池从PermGen区移到了Java堆区,执行intern操作时,如果常量池已经存在该字符串,则直接返回字符串引用,否则 复制该字符串对象的引用 到常量池中并返回 (首次出现原则)

具体区别分析见《深入分析String.intern和String常量的实现原理》

3.图解说明

2017/9/12 String.intern()_第1张图片
验证String.intern()方法在jdk1.6和1.7中的差异

上述代码在JDK1.6时输出false ,false  JDK 1.7时输出true,false


2017/9/12 String.intern()_第2张图片
JDK 1.6

从这幅图可以看出,在调用s1.intern()时,常量池中不存在StringTest,因此复制了一份StringTest的实例置于常量池中,并返回常量池中StringTest的引用,而s1指向的是Java堆中的StringTest,二者并不相同,返回false;

java字符串本身就在常量池中存在(可能是jvm虚拟机放进去的)。这时候调用s2.intern(),返回的是常量池中java 的引用,s2指向的是Java堆中的java,二者并不相同,返回false。

2017/9/12 String.intern()_第3张图片
JDK 1.7

JDK1.7时,常量池被移到了java堆区。在常量池中没有找到StringTest,只是在常量池中记录下首次出现的实例地址,因此s1.intern()和s1指向的是同一个StringTest,所以结果为true;

而在常量池中找到了java,返回的是常量池中java的地址,与s2不想同。

因此JDK1.7中输出如下:

2017/9/12 String.intern()_第4张图片
JDK 1.7输出结果

需要注意的是,s3.intern()==s3也返回false。

以下是自己的推测;

(1)根据第1条,new String(“abc”)应该是等价于new StringBuilder(“abc”).toString()。 s3会在字符串常量池中创建“StringTest”对象,也会在对中创建对象。因此s3.intern()中StringTest不符合首次出现,不会复制指向堆中StringTest的引用到常量池中,因此s3.intern()与s3不相等。

(2) 而s1中,应该是常量池存在String,Test。但是不存在StringTest,仍然符合首次出现原则,因此会复制堆中StringTest的引用到常量池中。

上述(2),用“计算机软件进行验证”。

2017/9/12 String.intern()_第5张图片
常量池不存在“计算机”与“软件”


2017/9/12 String.intern()_第6张图片
s1的建立在常量池中存放了“计算机”和“软件”

从上述结果验证了自己推测的(2)。s1在常量池中建立了“计算机”和“软件”对象。  这样s4.intern()和s5.intern()都不符合首次出现原则,因此返回false。

你可能感兴趣的:(2017/9/12 String.intern())