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 - finalVariabel :
Variabel tipe atau tipe primitif String, yaitu finaldan diinisialisasi dengan ekspresi konstanta waktu kompilasi (§15.28), disebut variabel konstan .
Juga dari JLS §15.28 - Ekspresi Konstan:
Kompilasi ekspresi konstan tipe waktu Stringselalu "diinternir" sehingga dapat berbagi contoh unik, menggunakan metode ini String#intern().
Ini tidak terjadi dalam contoh kode pertama Anda, di mana Stringvariabel tidak final. Jadi, mereka bukan ekspresi konstan waktu kompilasi. Operasi penggabungan di sana akan ditunda hingga runtime, sehingga mengarah ke penciptaan Stringobjek baru . Anda dapat memverifikasi ini dengan membandingkan kode byte kedua kode.
Contoh kode pertama (bukan finalversi) 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 strdan ingdalam dua variabel terpisah, dan menggunakan StringBuilderuntuk melakukan operasi penggabungan.
Sedangkan, contoh kode kedua Anda ( finalversi) 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 stringpada waktu kompilasi, yang dimuat oleh ldcoperasi pada langkah 0. Kemudian literal string kedua dimuat oleh ldcoperasi dalam langkah 7. Itu tidak melibatkan pembuatan Stringobjek baru saat runtime. String sudah dikenal pada waktu kompilasi, dan mereka diinternir.