JDK1.8下String常量池测试结果疑惑及技术咨询
JDK1.8 String常量池问题解析
先看测试代码:
// Test1 String sa = new String("lmn"); String sa1 = new String("opq"); StringBuilder stringBuilder = new StringBuilder().append(sa).append(sa1); String sa2 = stringBuilder.toString(); String sa3 = sa2.intern(); String sa4 = "lmnopq"; System.out.println("sa2 == sa3 ? " + (sa2 == sa3)); // true why? System.out.println("sa3 == sa4 ? " + (sa3 == sa4)); // true // Test2 String sss = new String("ghi") + new String("hjk"); String sss1 = sss.intern(); System.out.println("sss == sss1 ? " + (sss == sss1)); // true why? // Test3 String sc = new String("rszt") + new String("zuvw"); String sc1 = "rsztzuvw"; String sc2 = sc.intern(); System.out.println("sc == sc1 ? " + (sc == sc1)); // false why?
问题1:为何sa2 == sa3成立?"lmnopq"何时存入String常量池?
- JDK1.8中
String.intern()的逻辑是:检查常量池是否存在内容匹配的字符串。如果不存在,直接将堆中当前字符串的引用存入常量池,而非复制新对象到常量池。 sa2是StringBuilder.toString()生成的堆字符串,此时常量池中还没有"lmnopq"。调用sa2.intern()时,因常量池无匹配项,sa2的引用被存入常量池,sa3作为intern()的返回值,就是sa2本身的引用,因此sa2 == sa3成立。- "lmnopq"存入常量池的时机就是调用
sa2.intern()的时候。后续sa4 = "lmnopq"会直接引用常量池中的sa2引用,所以sa3 == sa4也成立。
问题2:sss == sss1的原因是否与sa2 == sa3一致?
- 完全一致。
new String("ghi") + new String("hjk")被优化为StringBuilder.append()后,sss本质就是StringBuilder.toString()生成的堆字符串,此时常量池中没有"ghihjk"。调用sss.intern()时,同样因常量池无匹配项,sss的引用被存入常量池,sss1返回的就是sss的引用,因此sss == sss1。
问题3:Test2与Test3逻辑相似,仅在sc.intern()前添加了String sc1 = "rsztzuvw";,为何此时sc != sc1?
String sc1 = "rsztzuvw";会先触发常量池初始化:JVM会创建"rsztzuvw"字符串对象并放入常量池,sc1直接引用常量池中的该对象。- 后续调用
sc.intern()时,常量池中已存在"rsztzuvw",因此intern()直接返回常量池中的对象引用(即sc1的引用),而非sc的堆引用。sc是堆中对象,sc1是常量池对象,两者引用不同,所以sc == sc1为false。
内容的提问来源于stack exchange,提问作者Pai
相关产品推荐
相关产品推荐

