Setiap literal "java" yang muncul di kode program tidak serta-merta membuat objek baru saat dieksekusi. JVM mengelola gudang khusus bernama string pool (juga disebut string intern pool): setiap literal String di program ditempatkan di sana tepat satu kali, lalu dipakai bersama oleh semua pemakaian yang isinya sama. Hemat memori yang dihasilkan cukup besar — teks yang sama sering muncul berkali-kali di program nyata. Chapter ini menyelidiki perilaku pool lewat operator ==, membedah perbedaan literal versus new String, lalu memperkenalkan method intern() untuk menyatukan String buatan runtime ke dalam pool.

Literal Bernasib Satu Objek #

Operator == pada variabel referensi membandingkan alamat objek yang ditunjuk, bukan isinya. Sifat tersebut menjadikan == alat ukur yang tepat untuk menyelidiki string pool: bila dua variabel literal menghasilkan == bernilai true, keduanya menunjuk objek yang sama persis di pool.

java KolamString.java
public class KolamString {
    public static void main(String[] args) {
        String a = "java";
        String b = "java";
        String c = new String("java");
        String d = c.intern();

        System.out.println("a == b           : " + (a == b));
        System.out.println("a == c           : " + (a == c));
        System.out.println("a == d           : " + (a == d));
        System.out.println("hashCode a       : " + a.hashCode());
        System.out.println("hashCode c       : " + c.hashCode());

        String gabunganKonstanta = "ja" + "va";
        System.out.println("a == \"ja\"+\"va\"  : " + (a == gabunganKonstanta));

        String bagian = "ja";
        String gabunganRuntime = bagian + "va";
        System.out.println("a == bagian+\"va\": " + (a == gabunganRuntime));
        System.out.println("a == intern()   : " + (a == gabunganRuntime.intern()));
    }
}

Output yang Dihasilkan:

text
a == b           : true
a == c           : false
a == d           : true
hashCode a       : 3254818
hashCode c       : 3254818
a == "ja"+"va"  : true
a == bagian+"va": false
a == intern()   : true

Mari kita telaah baris-baris kode di atas:

  1. Baris 4-5 (String a = "java"; String b = "java";): literal "java" dijadwalkan compiler masuk pool. Saat JVM memuat class, literal tersebut tinggal satu objek — a dan b menunjuk objek yang sama, dibuktikan a == b bernilai true.
  2. Baris 6 (String c = new String("java");): constructor new String secara eksplisit membuat objek baru di heap di luar pool, sekalipun isinya identik. Hasilnya a == c bernilai false — dua objek berbeda dengan isi sama.
  3. Baris 7 (c.intern()): method intern() mengembalikan objek dari pool yang isinya sama dengan c. Karena "java" sudah ada di pool, d menunjuk objek yang sama dengan a, sehingga a == d bernilai true.
  4. Baris 12-13 (hashCode): kode hash dihitung dari isi karakter, bukan dari alamat, sehingga a dan c menghasilkan angka yang sama (3254818) meski objeknya berbeda. Inilah sebabnya HashMap memakai hashCode dan equals, bukan ==.
  5. Baris 15 ("ja" + "va"): penggabungan dua konstanta dilakukan compiler javac saat kompilasi — hasilnya sudah menjadi literal "java" di pool sebelum program berjalan, sehingga perbandingan bernilai true.
  6. Baris 18-19 (bagian + "va"): bagian adalah variabel, sehingga penggabungan hanya bisa terjadi saat runtime dan menghasilkan objek baru di heap — perbandingan == bernilai false. Memanggil intern() pada hasilnya menyatukan kembali ke objek pool, dan perbandingan kembali true.

Kapan Pool Bekerja dan Kapan Tidak #

Aturannya dapat dirangkum dalam tabel ringkas berikut.

Sumber StringLokasi objekMenunjuk objek pool?
Literal "java"string poolya
Konstanta "ja" + "va"string poolya (digabung compiler saat kompilasi)
new String("java")heaptidak
Penggabungan runtime s + theaptidak (sebelum intern())
intern()string poolya

Yang perlu dicamkan: pool adalah optimasi memori, bukan mekanisme pembandingan isi. Kode yang benar tetap memakai equals() untuk membandingkan isi — pokok bahasan Chapter String Comparison. Pool paling banyak membantu pada teks pendek yang berulang (label, key konfigurasi, nama bulan); teks rakitan runtime yang panjang dan dipakai sekali tidak akan pernah masuk pool kecuali kita memanggil intern() secara sadar, dan memanggil intern() secara massal justru membebani pool itu sendiri.

Pemahaman tentang referensi versus isi kini utuh. Saatnya membahas tiga alat pembanding String dengan peran yang tepat untuk masing-masing: equals untuk isi, == untuk identitas objek, dan compareTo untuk urutan.

Referensi #

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

KolamString.java

Unduh berkas
java
public class KolamString {
    public static void main(String[] args) {
        String a = "java";
        String b = "java";
        String c = new String("java");
        String d = c.intern();

        System.out.println("a == b           : " + (a == b));
        System.out.println("a == c           : " + (a == c));
        System.out.println("a == d           : " + (a == d));
        System.out.println("hashCode a       : " + a.hashCode());
        System.out.println("hashCode c       : " + c.hashCode());

        String gabunganKonstanta = "ja" + "va";
        System.out.println("a == \"ja\"+\"va\"  : " + (a == gabunganKonstanta));

        String bagian = "ja";
        String gabunganRuntime = bagian + "va";
        System.out.println("a == bagian+\"va\": " + (a == gabunganRuntime));
        System.out.println("a == intern()   : " + (a == gabunganRuntime.intern()));
    }
}