Java的String类记录
字符串常量池(string pool)中是否可以存放对象?
可以存放对象,从String类的本地方法intern()可以看出字符串常量池可以存放对象:

同时可以看出,这个方法是有返回值的。
JDK6和JDK7中,intern()方法有什么变化?
JDK7中,字符串常量池由方法区(永久代)移到了堆中,永久代也消失了,改用本地内存,改为了元空间。在JDK7和JDK8,如果以字面量的方式创建字符串实例:
String str = "hello";
那么,在字符串常量池会产生相应的对象,str指向这个实例。
如果以new的方式创建字符串对象:
String str = new String("hello");
网上的说法就开始众说纷纭。集中的一个疑问是,以这种方式创建字符串,到底堆中有没有创建对象?
String str = new String("hello");
String after_str = "hello";
System.out.println(str == after_str);
在这里,需要在println这行下个断点:

很意外,不管是str还是after_str,其内部final的byte[]都指向了同一个地址。那么从这个简单的例子就可以说明,首先,str和after_str不是一个对象,一个在堆中,一个在常量池中,这个应该是普遍的共识,因为上面的输出结果是false,但是数组指向的是又是同一个地址。
如果把代码顺序更换一下:
String before_str = "hello";
String str = new String("hello");
System.out.println(str + before_str);

数组指向的地址仍然是一样的。
参看String类构造器:

注意这个构造器其实还是使用了字面量的方式创建字符串,只是将字符串的相关信息又copy了一份,这个对象应该是在堆中的,结合上面的情况,可以得知其内存结构其实是下面的图示:

用new的方式创建字符串,其实会在堆中产生一个String类的实例,但是这个String类的byte[]指向的却是字符串常量池中的byte[]。
new String("ab")会创建几个对象?
两个,一个对象是:new关键字在堆空间创建的。另一个对象是:字符串常量池中的对象。
new String("a") + new String("b")会创建几个对象?
对象1:StringBuilder
对象2:new String("a")
对象3:常量池中的"a"
对象4:new String("b")
对象5:常量池中的"b"
深入剖析:StringBuilder的toString()方法,返回了一个新的String
对象6: new String("ab")
注意,字符串常量池中此时不存在"ab",具体原因可以参考StringBuilder的toString()方法的字节码,字节码中没有ldc:

同样,类似问题诸如:
String str1 = new String("ABC") + "ABC"; 在字符串常量池中创建几个实例?
答案也是1个。(ABC)
JDK7及以后intern()方法的变化
再来看这个问题:
public class Test {
public static void main(String[] args) {
String str1 = new String("ABC") + "ABC";
System.out.println(str1.intern() == str1);
}
}
首先需要认识到,"+"会调用StringBuilder的append()方法,所以常量池中在没有intern()之前,并没有"ABCABC"的任何信息。
在JDK6,输出结果是false,但在JDK7,输出结果就是true了。
在JDK6中,intern()方法会在永久代创建一个"ABCABC"的对象,和堆中new出来的对象显然不是一个地址,所以是false。但JDK7将字符串常量池从永久代移到了堆中,由此发生了相应的变化,如果调用intern()方法的时候,发现常量池中没有存在堆空间中此时存在的字符串实例,就会将堆空间的地址引用存放到字符串常量池中,所以比较两端都是字符串在堆中的地址,结果是true。
总结
究其原因,产生混淆的根本在于,用new的方式创建字符串,本身也调用了通过字面量创建字符串的构造方法,所以字符串常量池中是有该对象。利用拼接操作去创建字符串(拼接的两端不都是常量的情况下),调用了StringBuilder的append()方法,是没有通过字面量创建字符串,所以字符串常量池中没有该实例,这里的逻辑和JDK版本无关。JDK7之后影响了的是intern()方法。
有一点需要注意,JDK7开始,字符串常量池可以存放引用了。
本文来自博客园,作者:imissinstagram,转载请注明原文链接:https://www.cnblogs.com/LostSecretGarden/p/14830704.html

浙公网安备 33010602011771号