JLS
JLS 7 3.10.5 mendefinisikannya dan memberikan contoh praktis:
Selain itu, string literal selalu merujuk ke instance String kelas yang sama. Ini karena string literal - atau, lebih umum, string yang merupakan nilai ekspresi konstan (§15.28) - "diinternir" sehingga dapat berbagi contoh yang unik, menggunakan metode String.intern.
Contoh 3.10.5-1. String Literal
Program yang terdiri dari unit kompilasi (§7.3):
package testPackage;
class Test {
public static void main(String[] args) {
String hello = "Hello", lo = "lo";
System.out.print((hello == "Hello") + " ");
System.out.print((Other.hello == hello) + " ");
System.out.print((other.Other.hello == hello) + " ");
System.out.print((hello == ("Hel"+"lo")) + " ");
System.out.print((hello == ("Hel"+lo)) + " ");
System.out.println(hello == ("Hel"+lo).intern());
}
}
class Other { static String hello = "Hello"; }
dan unit kompilasi:
package other;
public class Other { public static String hello = "Hello"; }
menghasilkan output:
true true true true false true
JVMS
JVMS 7 5.1 mengatakan bahwa interning diimplementasikan secara ajaib dan efisien dengan CONSTANT_String_info
struct khusus (tidak seperti kebanyakan objek lain yang memiliki representasi lebih umum):
Literal string adalah referensi ke turunan dari String kelas, dan diturunkan dari struktur CONSTANT_String_info (§4.4.3) dalam representasi biner dari kelas atau antarmuka. Struktur CONSTANT_String_info memberikan urutan titik kode Unicode yang membentuk string literal.
Bahasa pemrograman Java mensyaratkan bahwa literal string identik (yaitu, literal yang berisi urutan titik kode yang sama) harus merujuk ke instance String kelas yang sama (JLS §3.10.5). Selain itu, jika metode String.intern dipanggil pada sembarang string, hasilnya adalah referensi ke instance kelas yang sama yang akan dikembalikan jika string itu muncul sebagai literal. Dengan demikian, ekspresi berikut harus memiliki nilai true:
("a" + "b" + "c").intern() == "abc"
Untuk mendapatkan string literal, Java Virtual Machine memeriksa urutan poin kode yang diberikan oleh struktur CONSTANT_String_info.
Jika metode String.intern sebelumnya telah dipanggil pada turunan String kelas yang berisi urutan titik kode Unicode yang identik dengan yang diberikan oleh struktur CONSTANT_String_info, maka hasil derivasi string literal adalah referensi ke turunan String String yang sama.
Jika tidak, instance baru String kelas dibuat berisi urutan titik kode Unicode yang diberikan oleh struktur CONSTANT_String_info; referensi ke instance kelas adalah hasil derivasi string literal. Akhirnya, metode intern instance String baru dipanggil.
Bytecode
Mari kita mendekompilasi beberapa bytecode OpenJDK 7 untuk melihat tindakan interning.
Jika kami mendekompilasi:
public class StringPool {
public static void main(String[] args) {
String a = "abc";
String b = "abc";
String c = new String("abc");
System.out.println(a);
System.out.println(b);
System.out.println(a == c);
}
}
yang kita miliki di kolam konstan:
#2 = String #32 // abc
[...]
#32 = Utf8 abc
dan main
:
0: ldc #2 // String abc
2: astore_1
3: ldc #2 // String abc
5: astore_2
6: new #3 // class java/lang/String
9: dup
10: ldc #2 // String abc
12: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V
15: astore_3
16: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
19: aload_1
20: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
23: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
26: aload_2
27: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
33: aload_1
34: aload_3
35: if_acmpne 42
38: iconst_1
39: goto 43
42: iconst_0
43: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
Perhatikan caranya:
0
dan 3
: ldc #2
konstanta yang sama dimuat (literal)
12
: contoh string baru dibuat (dengan #2
sebagai argumen)
35
: a
dan c
dibandingkan sebagai objek biasa denganif_acmpne
Representasi string konstan cukup ajaib pada bytecode:
dan kutipan JVMS di atas tampaknya mengatakan bahwa setiap kali Utf8 menunjuk adalah sama, maka instance identik dimuat oleh ldc
.
Saya telah melakukan tes serupa untuk bidang, dan:
static final String s = "abc"
menunjuk ke tabel konstan melalui Atribut ConstantValue
- bidang non-final tidak memiliki atribut itu, tetapi masih dapat diinisialisasi dengan
ldc
Kesimpulan : ada dukungan bytecode langsung untuk kumpulan string, dan representasi memori efisien.
Bonus: bandingkan dengan kelompok Integer , yang tidak memiliki dukungan bytecode langsung (yaitu tidak ada CONSTANT_String_info
analog).