前言

 在之前的面试经历中,对于String的考察还是挺频繁的,大致考察以下几个知识点:

  • String 常量池
  • new String()
  • == 和 equals 的区别
  • native 方法 String.intern()
    虽然面试中大体答对了,但是今天早上微信群里的一个问题我却答不上来,这个问题是这样的:
    String str3 = "what";     String str4 = str3 + " a nice day";     //运行时, + 相当于 new,所以堆中会有 "what a nice day"对象,常量池中会有"what"," a nice day"两个对象,而不会有 "what a nice day"对象。     //这句话大佬们看看对不对啊,我怎么感觉不对啊     //常量池不会有"what a nice day" 对象吗?

看完这个问题,说实话我也是有点懵的,我只是知道 "what a nice day"不会在常量池,但是不知道具体的原因,后来群里的同学说 + 号是调用了 StringBuffer 的append 方法。我去证实了,发现确实调用了 append 方法,但是当时没有 调用toString()方法,我很疑惑。(最后经过证实,是StringBuilder的append 方法,不是StringBuffer)。

代码验证

 public static void main(String[] args) {         //#1         String str1 = "what";         //#2         String str2 = str1 + " a nice day";         //#3         System.out.println("what a nice day".equals(str2));         //#4         System.out.println("what a nice day" == str2);     }

现在有以下几个问题,小伙伴们看看是否能答出来,即使答出来了,你知道为什么吗?

  • #1 str1 存放位置?
  • #2 str2 存放位置?
  • #3 结果是 true 还是 false?
  • #4 结果是 true 还是 false?
  • #5 "what a nice day" 存放在哪个位置呢?

解答分析(基于JDK1.8)

下面也不靠猜,我们直接查看生成的字节码:

localhost:test didi$ javap -verbose -p Main.class Classfile /develop/project/string-test/out/production/classes/com/fanpan26/string/test/Main.class   Last modified 2019-11-29; size 972 bytes   MD5 checksum 1d1f1a23bfe85c2f88d2f767e8aac314   Compiled from "Main.java" public class com.fanpan26.string.test.Main   minor version: 0   major version: 52   flags: ACC_PUBLIC, ACC_SUPER Constant pool:    #1 = Methodref          #13.#34        // java/lang/Object."<init>":()V    #2 = String             #35            // what    #3 = Class              #36            // java/lang/StringBuilder    #4 = Methodref          #3.#34         // java/lang/StringBuilder."<init>":()V    #5 = Methodref          #3.#37         // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;    #6 = String             #38            //  a nice day    #7 = Methodref          #3.#39         // java/lang/StringBuilder.toString:()Ljava/lang/String;    #8 = Fieldref           #40.#41        // java/lang/System.out:Ljava/io/PrintStream;    #9 = String             #42            // what a nice day   #10 = Methodref          #43.#4