管理 java.lang.String 的 + 号操作到底做了什么事情?
前言
在之前的面试经历中,对于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