一個關(guān)于Java字符串對象問題的詳細解答
今天下班的路上,看到有人問這樣一個問題:

我看到這個問題的第一眼也有點懵。
但如果把問題換成以下代碼,答案對于我來說還是非常清晰的。
- String str = "test" + "1";
 
但是當一個字符串和一個整數(shù)相加時,會創(chuàng)建幾個對象呢?
作為老司機,深知實踐是檢驗真理的唯一標準,動手才是硬道理。
代碼清單如下:
- public class Hello {
 - public static void main(String[] args) {
 - String str = "test" + 1;
 - System.out.println(str);
 - }
 - }
 
編譯以上代碼,執(zhí)行,控制臺輸出沒有任何異議。

要看到創(chuàng)建了幾個對象,我們需要反編譯 Hello.class 文件,得到 java 字節(jié)碼指令。

看到 main 方法的字節(jié)碼指令,一切已經(jīng)真相大白。
其實,作為一個老司機,早就應(yīng)該想到是這樣的結(jié)果。
可是,面對這樣一道面試題,竟然還是還是蒙圈了。
那我們來解釋一下 main 方法的第一條字節(jié)碼指令。
- 0: ldc
 
- ldc 的意思是 LoaD Constant,即從常量池中加載一個常量并壓入(push)到操作數(shù)棧(operand stack)。
 - #2 是常量池中索引,表示常量池中的第2項。
 
關(guān)于 ldc 字節(jié)碼指令的詳細說明,請參考官方文檔,連接地址為:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.ldc。
常量池中的第2個常量到底是什么,我們還需要使用 javap 命令來獲得。
- C:\Users\Thinkpad\Desktop>javap -v Hello.class
 - Classfile /C:/Users/Thinkpad/Desktop/Hello.class
 - Last modified 2021-8-12; size 415 bytes
 - MD5 checksum d350245a83d24798f2269149002970f5
 - Compiled from "Hello.java"
 - public class Hello
 - minor version: 0
 - major version: 52
 - flags: ACC_PUBLIC, ACC_SUPER
 - Constant pool:
 - #1 = Methodref #6.#15 // java/lang/Object."<init>":()V
 - #2 = String #16 // test1
 - #3 = Fieldref #17.#18 // java/lang/System.out:Ljava/io/PrintStream;
 - #4 = Methodref #19.#20 // java/io/PrintStream.println:(Ljava/lang/String;)V
 - #5 = Class #21 // Hello
 - #6 = Class #22 // java/lang/Object
 - #7 = Utf8 <init>
 - #8 = Utf8 ()V
 - #9 = Utf8 Code
 - #10 = Utf8 LineNumberTable
 - #11 = Utf8 main
 - #12 = Utf8 ([Ljava/lang/String;)V
 - #13 = Utf8 SourceFile
 - #14 = Utf8 Hello.java
 - #15 = NameAndType #7:#8 // "<init>":()V
 - #16 = Utf8 test1
 - #17 = Class #23 // java/lang/System
 - #18 = NameAndType #24:#25 // out:Ljava/io/PrintStream;
 - #19 = Class #26 // java/io/PrintStream
 - #20 = NameAndType #27:#28 // println:(Ljava/lang/String;)V
 - #21 = Utf8 Hello
 - #22 = Utf8 java/lang/Object
 - #23 = Utf8 java/lang/System
 - #24 = Utf8 out
 - #25 = Utf8 Ljava/io/PrintStream;
 - #26 = Utf8 java/io/PrintStream
 - #27 = Utf8 println
 - #28 = Utf8 (Ljava/lang/String;)V
 
我們看到常量池(Constant pool)的第二項是:test1。
也就是說,javac 在編譯代碼過程中知道:
- 字符串 "test" 是一個字面值常量
 - 整數(shù) 1 是一個字面值常量
 
所以,編譯器將兩個常量在編譯過程中,計算然后合并成一個字符串常量test1,并保存在常量池中。
所以在代碼執(zhí)行過程中,根本就沒有創(chuàng)建任何對象。
本文轉(zhuǎn)載自微信公眾號「Golang In Memory」
















 
 
 






 
 
 
 