Apa perbedaan antara "teks" dan String baru ("teks")?


195

Apa perbedaan antara kedua pernyataan berikut ini?

String s = "text";

String s = new String("text");


Siapa pun tolong balas ini. String a = "Java"; String b = "Java"; System.out.println (a == b); true // tetapi System.out.println ("a == b?" + a == b); // palsu ...
Energi

saya tidak mengerti ketika saya menambahkan beberapa komentar ("a == b?) => hasil saya menjadi SALAH. mengapa?
Energy

@ Energi Hasil adalah falsekarena urutan operasi menentukan bahwa + operator berjalan lebih dulu, menyatukan "a == b?" dengan a untuk membuat String "a == b? Java". Kemudian ekspresi "a==b?Java" == bbernilai false.
Allison B

@ AllisonB mengerti, terima kasih banyak!
Energi

Jawaban:


187

new String("text"); secara eksplisit membuat instance Stringobjek baru dan berbeda secara referensi ; String s = "text";dapat menggunakan kembali instance dari kumpulan string konstan jika tersedia.

Anda sangat jarang ingin menggunakan new String(anotherString)konstruktor. Dari API:

String(String original): Menginisialisasi objek yang baru dibuat String sehingga mewakili urutan karakter yang sama dengan argumen; dengan kata lain, string yang baru dibuat adalah salinan dari string argumen. Kecuali jika salinan asli dari dokumen asli diperlukan, penggunaan konstruktor ini tidak diperlukan karena string tidak dapat diubah.

Pertanyaan-pertanyaan Terkait


Apa perbedaan referensial berarti

Periksa cuplikan berikut:

    String s1 = "foobar";
    String s2 = "foobar";

    System.out.println(s1 == s2);      // true

    s2 = new String("foobar");
    System.out.println(s1 == s2);      // false
    System.out.println(s1.equals(s2)); // true

==pada dua jenis referensi adalah perbandingan identitas referensi. Dua objek yang equalsbelum tentu ==. Biasanya salah untuk digunakan ==pada tipe referensi; sebagian besar waktu equalsharus digunakan sebagai gantinya.

Meskipun demikian, jika untuk alasan apa pun Anda perlu membuat dua equalstetapi bukan ==string, Anda dapat menggunakan new String(anotherString)konstruktor. Perlu dikatakan lagi, bagaimanapun, bahwa ini sangat aneh, dan jarang niat.

Referensi

Masalah terkait


3
Jika saya menulis: String s = new String ("abc"); Dan sekarang saya menulis: String s = "abc"; Will String s = "abc"; membuat String literal baru di kumpulan String?
Kaveesh Kanwal

Mengapa tidak ada yang menjawab pertanyaan sebelumnya?
zeds

2
@ KaveeshKanwal Tidak, literal tidak akan diduplikasi. Seperti yang Anda lihat ada 2 "abc"s. Hanya satu dari mereka yang akan pergi ke kolam String, dan yang lain akan merujuknya. Lalu ada syang akan menjadi objek baru yang tepat.
Kayaman

1
@Kaveesh Kanwal - String s = new String ("abc") hanya akan membuat objek String baru dengan nilai "abc". Dan pernyataan ke-2 akan memeriksa apakah string literal "abc" sudah ada di String Pool atau tidak. Jika sudah ada maka referensi ke yang sudah ada dikembalikan dan jika tidak maka literal baru ("abc") dibuat di kolam String. Semoga ini menyelesaikan kueri Anda !!
user968813

Tidak ada 'mungkin' tentang itu. Kompiler harus mengumpulkan string literal. JLS 3.10.5 .
Marquis of Lorne

119

Literal string akan masuk ke String Constant Pool .

Cuplikan di bawah ini mungkin membantu Anda memahaminya secara visual untuk mengingatnya lebih lama.

masukkan deskripsi gambar di sini


Pembuatan objek baris demi baris:

String str1 = new String("java5");

Menggunakan string literal "java5" di konstruktor, nilai string baru disimpan dalam kumpulan string konstan. Menggunakan operator baru, objek string baru dibuat di heap dengan nilai "java5".

String str2 = "java5"

Referensi "str2" menunjuk ke nilai yang sudah tersimpan dalam kumpulan konstanta string

String str3 = new String(str2);

Objek string baru dibuat di heap dengan nilai yang sama dengan referensi oleh "str2"

String str4 = "java5";

Referensi "str4" menunjuk ke nilai yang sudah tersimpan dalam kumpulan konstanta string

Total objek: Heap - 2, Pool - 1

Bacaan lebih lanjut tentang komunitas Oracle


1
Jawaban yang bagus .. tapi kami ingin tahu bahwa sekarang saya akan mengubah nilai str1 = "java6" maka akan mengubah nilai str4?
CoronaPintu

2
ya saya telah memeriksa itu tidak akan mengubah nilai str4
CoronaPintu

@Braj Bisakah Anda memberikan dokumentasi pernyataan Penjawab Anda?
Basil Bourque

@Braj: Apakah header untuk 'Heap' & 'pool' di tabel seharusnya terbalik?
Rahul Kurup

Tidak benar. Kumpulan konstan dibuat pada waktu kompilasi, bukan pada waktu eksekusi. Jangan gunakan format kutipan untuk teks yang tidak dikutip.
Marquis of Lorne

15

Satu menciptakan sebuah String di String Constant Pool

String s = "text";

yang lain membuat string di pool konstan ( "text") dan string lain di ruang heap normal ( s). Kedua string akan memiliki nilai yang sama, yaitu "teks".

String s = new String("text");

s kemudian hilang (memenuhi syarat untuk GC) jika nantinya tidak digunakan.

String literal di sisi lain digunakan kembali. Jika Anda menggunakan "text"banyak tempat di kelas Anda, sebenarnya hanya satu dan hanya satu String (yaitu beberapa referensi ke string yang sama di kumpulan).


String di kolam konstan tidak pernah hilang. Apakah Anda bermaksud mengatakan 'hilang' jika nanti tidak digunakan?
Marquis of Lorne

@ EJP: ya, maksudku "s". Terima kasih telah memperhatikan. Saya akan memperbaiki pertanyaannya.

9

JLS

Konsep ini disebut "magang" oleh JLS.

Bagian yang relevan dari JLS 7 3.10.5 :

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 :

Literal string adalah referensi ke instance 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 instance 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 instance String String kelas yang sama.

  • Jika tidak, instance baru String kelas dibuat yang 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

Juga penting untuk melihat implementasi bytecode pada OpenJDK 7.

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:

  • 0dan 3: ldc #2konstanta yang sama dimuat (literal)
  • 12: contoh string baru dibuat (dengan #2 sebagai argumen)
  • 35: adan cdibandingkan 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_infoanalog).


2

@ Burj: Saya pikir Anda telah menyebutkan sebaliknya. mohon koreksi saya jika saya salah

Pembuatan objek baris demi baris:

String str1 = String baru ("java5")

   Pool- "java5" (1 Object)

   Heap - str1 => "java5" (1 Object)

String str2 = "java5"

  pool- str2 => "java5" (1 Object)

  heap - str1 => "java5" (1 Object)

String str3 = String baru (str2)

  pool- str2 => "java5" (1 Object)

  heap- str1 => "java5", str3 => "java5" (2 Objects)

String str4 = "java5"

  pool - str2 => str4 => "java5" (1 Object)

  heap - str1 => "java5", str3 => "java5" (2 Objects)

str1tidak terlibat dalam nilai str2atau str3atau str4dengan cara apa pun.
Marquis of Lorne

1

Pikirkan "bla"menjadi seperti pabrik ajaib Strings.createString("bla")(semu). Pabrik memiliki kumpulan semua string yang belum dibuat dengan cara ini.

Jika dipanggil, ia memeriksa apakah sudah ada string di pool dengan nilai ini. Jika benar, ia mengembalikan objek string ini, maka untuk string yang diperoleh dengan cara ini memang objek yang sama.

Jika tidak, ia membuat objek string baru secara internal, menyimpannya di pool dan kemudian mengembalikannya. Jadi, ketika nilai string yang sama di-query di waktu berikutnya, ia mengembalikan instance yang sama.

Secara manual membuat new String("")menimpa perilaku ini dengan mem-bypass string literal string. Jadi kesetaraan harus selalu diperiksa menggunakan equals()yang membandingkan urutan karakter daripada persamaan referensi objek.


'Pabrik ajaib' yang Anda rujuk tidak lain adalah kompiler Java. Adalah kesalahan untuk menulis proses ini seolah-olah itu terjadi pada saat runtime.
Marquis of Lorne

1

Salah satu cara sederhana untuk memahami perbedaannya adalah di bawah ini: -

String s ="abc";
String s1= "abc";
String s2=new String("abc");

        if(s==s1){
            System.out.println("s==s1 is true");
        }else{
            System.out.println("s==s1 is false");
        }
        if(s==s2){
            System.out.println("s==s2 is true");
        }else{
            System.out.println("s==s2 is false");
        }

output adalah

s==s1 is true
s==s2 is false

Jadi String baru () akan selalu membuat instance baru.


1

Setiap literal String akan dibuat di dalam kumpulan literal string dan kumpulan tidak memungkinkan duplikat. Jadi jika dua atau lebih objek string diinisialisasi dengan nilai literal yang sama maka semua objek akan menunjuk ke literal yang sama.

String obj1 = "abc";
String obj2 = "abc";

"obj1" dan "obj2" akan menunjuk ke string literal yang sama dan pool string literal hanya akan memiliki satu literal "abc".

Ketika kita membuat objek kelas String menggunakan kata kunci baru, string yang dibuat tersebut disimpan dalam memori heap. Namun setiap string string yang dilewatkan sebagai parameter ke konstruktor kelas String disimpan dalam kumpulan string. Jika kita membuat banyak objek menggunakan nilai yang sama dengan operator baru, objek baru akan dibuat di heap setiap kali, karena operator baru ini harus dihindari.

String obj1 = new String("abc");
String obj2 = new String("abc");

"obj1" dan "obj2" akan menunjuk ke dua objek berbeda di heap dan string literal pool hanya akan memiliki satu "abc" literal.

Juga sesuatu yang perlu diperhatikan sehubungan dengan perilaku string adalah bahwa setiap penugasan atau penyatuan baru yang dilakukan pada string menciptakan objek baru dalam memori.

String str1 = "abc";
String str2 = "abc" + "def";
str1 = "xyz";
str2 = str1 + "ghi";

Sekarang dalam kasus di atas:
Baris 1: "abc" literal disimpan dalam kumpulan string.
Baris 2: literal "abcdef" disimpan di kumpulan string.
Baris 3: Literal "xyz" baru disimpan di kumpulan string dan "str1" mulai mengarah ke literal ini.
Baris 4: Karena nilai dihasilkan dengan menambahkan ke variabel lain, hasilnya disimpan dalam memori heap dan literal yang ditambahkan "ghi" akan diperiksa keberadaannya di kumpulan string dan akan dibuat karena tidak ada di kasus di atas.


0

Meskipun terlihat sama dari sudut pandang programmer, ini memiliki dampak kinerja yang besar. Anda ingin selalu menggunakan formulir pertama.


0
String str = new String("hello")

Ini akan memeriksa apakah kumpulan konstanta String sudah berisi String "halo"? Jika ada maka itu tidak akan menambah entri dalam string konstan pool. Jika tidak ada maka itu akan menambah entri dalam string konstan pool.

Objek akan dibuat di area memori tumpukan dan strtitik referensi ke objek yang dibuat di lokasi memori tumpukan.

jika Anda ingin strreferensi ke objek titik yang berisi dalam string konstan pool maka seseorang harus memanggil secara eksplisitstr.intern();

String str = "world";

Ini akan memeriksa apakah kumpulan konstanta String sudah berisi String "halo"? Jika ada maka itu tidak akan menambah entri dalam string konstan pool. Jika tidak ada maka itu akan menambah entri dalam string konstan pool.

Dalam kedua kasus di atas, strtitik referensi ke String "world"hadir di kumpulan Constant.


'Itu' menjadi kompiler Java. Literal string membuat entri unik dalam kumpulan konstan, pada waktu kompilasi. Merupakan kesalahan untuk menghentikan proses ini seolah-olah itu terjadi pada saat runtime ..
Marquis of Lorne

Bisakah Anda jelaskan apa yang salah dalam posting ini dengan jelas?
Jayesh

Apa yang salah dalam posting ini adalah bahwa string literal dikumpulkan pada waktu yang sama, seperti yang sudah saya katakan. Tidak ketika mengeksekusi kode, seperti pada jawaban Anda.
Marquis of Lorne

@ EJP Saya menghargai tanggapan Anda. Tolong tunjukkan garis yang salah dalam menjawab. Saya melihat semua jawaban di atas sama dengan apa yang saya tulis. Tolong bantu, saya ingin memperbaiki pemahaman saya. Terima kasih.
Jayesh

Anda telah menulis tentang seluruh proses seolah-olah semuanya terjadi ketika garis kode dieksekusi, yang, seperti yang telah saya katakan berulang kali, bukan itu masalahnya. Anda tidak dapat mengurangi semua itu menjadi satu 'garis persis' yang salah dalam jawaban Anda.
Marquis of Lorne

0

Saat Anda menyimpan String sebagai

String string1 = "Hello";

langsung, maka JVM membuat objek String dengan harga yang diberikan selama blok memori yang terpisah yang disebut String constant pool.

Dan setiap kali kita memiliki kecenderungan untuk mencoba dan menghasilkan String lain

String string2 = "Hello";

JVM memverifikasi apakah objek String dengan harga konstan ada atau tidak dalam kumpulan konstanta String, jika demikian, daripada membuat objek baru, JVM memberikan referensi objek yang ada ke variabel baru.

Dan ketika kita menyimpan String sebagai

String string = new String("Hello");

menggunakan kata kunci baru, objek baru dengan harga yang diberikan dibuat tidak peduli isi kumpulan konstanta String.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.