Ketika Anda mendeklarasikan variabel String
(yang tidak dapat diubah ) sebagai final
, dan menginisialisasinya dengan ekspresi konstanta waktu kompilasi, ia juga menjadi ekspresi konstanta waktu kompilasi, dan nilainya digarisbawahi oleh kompiler di mana ia digunakan. Jadi, dalam contoh kode kedua Anda, setelah menguraikan nilai-nilai, rangkaian string diterjemahkan oleh kompiler ke:
String concat = "str" + "ing"; // which then becomes `String concat = "string";`
yang bila dibandingkan "string"
akan memberi Anda true
, karena string literal diinternir .
Dari JLS §4.12.4 - final
Variabel :
Variabel tipe atau tipe primitif String
, yaitu final
dan diinisialisasi dengan ekspresi konstanta waktu kompilasi (§15.28), disebut variabel konstan .
Juga dari JLS §15.28 - Ekspresi Konstan:
Kompilasi ekspresi konstan tipe waktu String
selalu "diinternir" sehingga dapat berbagi contoh unik, menggunakan metode ini String#intern()
.
Ini tidak terjadi dalam contoh kode pertama Anda, di mana String
variabel tidak final
. Jadi, mereka bukan ekspresi konstan waktu kompilasi. Operasi penggabungan di sana akan ditunda hingga runtime, sehingga mengarah ke penciptaan String
objek baru . Anda dapat memverifikasi ini dengan membandingkan kode byte kedua kode.
Contoh kode pertama (bukan final
versi) dikompilasi ke kode byte berikut:
Code:
0: ldc #2; //String str
2: astore_1
3: ldc #3; //String ing
5: astore_2
6: new #4; //class java/lang/StringBuilder
9: dup
10: invokespecial #5; //Method java/lang/StringBuilder."<init>":()V
13: aload_1
14: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: aload_2
18: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: invokevirtual #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
24: astore_3
25: getstatic #8; //Field java/lang/System.out:Ljava/io/PrintStream;
28: aload_3
29: ldc #9; //String string
31: if_acmpne 38
34: iconst_1
35: goto 39
38: iconst_0
39: invokevirtual #10; //Method java/io/PrintStream.println:(Z)V
42: return
Jelas itu menyimpan str
dan ing
dalam dua variabel terpisah, dan menggunakan StringBuilder
untuk melakukan operasi penggabungan.
Sedangkan, contoh kode kedua Anda ( final
versi) terlihat seperti ini:
Code:
0: ldc #2; //String string
2: astore_3
3: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
6: aload_3
7: ldc #2; //String string
9: if_acmpne 16
12: iconst_1
13: goto 17
16: iconst_0
17: invokevirtual #4; //Method java/io/PrintStream.println:(Z)V
20: return
Jadi secara langsung inline variabel akhir untuk membuat String string
pada waktu kompilasi, yang dimuat oleh ldc
operasi pada langkah 0
. Kemudian literal string kedua dimuat oleh ldc
operasi dalam langkah 7
. Itu tidak melibatkan pembuatan String
objek baru saat runtime. String sudah dikenal pada waktu kompilasi, dan mereka diinternir.