相关的面试题
Q1: String s = new String(“abc”); 定义了几个对象?
Q2: 如何理解String的intern 方法?
A1:若常量池中已经存在“abc”,则直接引用,也就是此时只会创建一个对象;若常量池中不存在这个“abc”,则会先创建后引用,也就是两个。
A2:当一个String实例调用intern方法时,jvm会查找常量池中是否有相同Unicode的字符串常量,如果有,则返回其引用,如果没有,则在常量池中增加一个Unicode等于Str的字符串并返回他的引用。
String a = "abc";
String b = new String("abc");
String c = new String("abc");
String d = new String("abc").intern();
System.out.println(a==b);
System.out.println(b==c);
System.out.println(b==d);
System.out.println(a==d);
结果:
false
false
false
true
字面量和运行时常量池
JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化。为了减少在JVM中创建的字符串的数量,字符串类维护了一个字符串常量池。
在JVM运行时区域的方法区中,有一块区域是运行时常量池,主要用来存储编译期生成的各种字面量和符号引用。
在运行期,new String(“Hollis”);执行到的时候,是要在Java堆中创建一个字符串对象的,而这个对象所对应的字符串字面量是保存在字符串常量池中的。但是,String s = new String(“Hollis”);,对象的符号引用s是保存在Java虚拟机栈上的,他保存的是堆中刚刚创建出来的的字符串对象的引用。
常量池中的“对象”是在编译期就确定好了的,在类被加载的时候创建的,如果类加载时,该字符串常量在常量池中已经有了,那这一步就省略了。堆中的对象是在运行期才确定的,在代码执行到new的时候创建的。
总结
new String 所谓的“如果有的话就直接引用”,指的是Java堆中创建的String对象中包含的字符串字面量直接引用字符串池中的字面量对象。也就是说,还是要在堆里面创建对象的。
而intern中说的“如果有的话就直接返回其引用”,指的是会把字面量对象的引用直接返回给定义的对象。这个过程是不会在Java堆中再创建一个String对象的。
intern和new的最大区别就是intern可以动态的向常量池中添加常量或者直接返回常量而不必重新在堆里重新生成对象。