一.问题引入
今天被同事问到一个问题:以下两段代码为什么返回结果不同
String s1= new String("a") + new String("b");
String s2 = s1.intern();
System.out.println(s1 == s2); // true
String s3 = new String("fg");
String s4 = s3.intern();
System.out.println(s3 == s4); //false
二.思考问题
分析以上问题,不难看出两段代码的结果不同就是第一行代码导致的,所以问题的本质就转变为new String("a") + new String("b")和new String("fg")到底有什么区别,进一步分析就发现问题关键在于new String("abc")的时候,StringTable中是否会创建对象,上网去查了一下发现答案不一致,于是亲自去实践了一番,发现流程是这样的,字面量“abc”会在字节码的常量池中,但是基于String的懒加载机制,这时候“abc”还仅仅是符号,而不是对象,执行到new的这一行才真正转变为字符串对象,并被放入字符串常量池中,然后会通过new String创建一个对象放入堆中,所以执行new String("abc")其实是创建了两个对象。
三.解决问题
基于以上我们就不难分析出问题的结果:
第一段代码中实际创建了这样几个对象:StringTable中的“a”,"b",堆中创建的new String("a")和new String("对象"),用于字符串拼接的StringBuilder对象,创建完成后调用toString方法生成的对象,相当于new String("ab"),关键就在于这个对象是不会在StringTable创建的,所以当执行s1.intern方法时,就会在StringTable中创建“ab”,并返回它的引用也就是s1,故为true
执行intern方法前:
执行intern方法后:
第二段代码实际创建了两个对象,StringTable中的“fg”和堆中创建的new String("fg"),调用s3.intern方法返回的就是池中的那个对象,这和堆中的对象显然不是同一个,故为false 如下图所示: