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 dibuatString 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.
==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.
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.
Pembuatan objek baris demi baris:
String str1 =newString("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 =newString(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
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 =newString("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).
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.
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:
publicclassStringPool{publicstaticvoid main(String[] args){String a ="abc";String b ="abc";String c =newString("abc");System.out.println(a);System.out.println(b);System.out.println(a == c);}}
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=newString("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.
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.
"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.
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.
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 =newString("Hello");
menggunakan kata kunci baru, objek baru dengan harga yang diberikan dibuat tidak peduli isi kumpulan konstanta String.
false
karena urutan operasi menentukan bahwa + operator berjalan lebih dulu, menyatukan "a == b?" dengan a untuk membuat String "a == b? Java". Kemudian ekspresi"a==b?Java" == b
bernilai false.Jawaban:
new String("text");
secara eksplisit membuat instanceString
objek 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:Pertanyaan-pertanyaan Terkait
Apa perbedaan referensial berarti
Periksa cuplikan berikut:
==
pada dua jenis referensi adalah perbandingan identitas referensi. Dua objek yangequals
belum tentu==
. Biasanya salah untuk digunakan==
pada tipe referensi; sebagian besar waktuequals
harus digunakan sebagai gantinya.Meskipun demikian, jika untuk alasan apa pun Anda perlu membuat dua
equals
tetapi bukan==
string, Anda dapat menggunakannew String(anotherString)
konstruktor. Perlu dikatakan lagi, bagaimanapun, bahwa ini sangat aneh, dan jarang niat.Referensi
class Object
-boolean Object(equals)
Masalah terkait
sumber
"abc"
s. Hanya satu dari mereka yang akan pergi ke kolam String, dan yang lain akan merujuknya. Lalu adas
yang akan menjadi objek baru yang tepat.Literal string akan masuk ke String Constant Pool .
Cuplikan di bawah ini mungkin membantu Anda memahaminya secara visual untuk mengingatnya lebih lama.
Pembuatan objek baris demi baris:
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".
Referensi "str2" menunjuk ke nilai yang sudah tersimpan dalam kumpulan konstanta string
Objek string baru dibuat di heap dengan nilai yang sama dengan referensi oleh "str2"
Referensi "str4" menunjuk ke nilai yang sudah tersimpan dalam kumpulan konstanta string
Total objek: Heap - 2, Pool - 1
Bacaan lebih lanjut tentang komunitas Oracle
sumber
Satu menciptakan sebuah String di String Constant Pool
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".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).sumber
JLS
Konsep ini disebut "magang" oleh JLS.
Bagian yang relevan dari JLS 7 3.10.5 :
JVMS
JVMS 7 5.1 mengatakan :
Bytecode
Juga penting untuk melihat implementasi bytecode pada OpenJDK 7.
Jika kami mendekompilasi:
yang kita miliki di kolam konstan:
dan
main
:Perhatikan caranya:
0
dan3
:ldc #2
konstanta yang sama dimuat (literal)12
: contoh string baru dibuat (dengan#2
sebagai argumen)35
:a
danc
dibandingkan sebagai objek biasa denganif_acmpne
Representasi string konstan cukup ajaib pada bytecode:
new String
)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 ConstantValueldc
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).sumber
@ Burj: Saya pikir Anda telah menyebutkan sebaliknya. mohon koreksi saya jika saya salah
Pembuatan objek baris demi baris:
String str1 = String baru ("java5")
String str2 = "java5"
String str3 = String baru (str2)
String str4 = "java5"
sumber
str1
tidak terlibat dalam nilaistr2
ataustr3
ataustr4
dengan cara apa pun.Pikirkan
"bla"
menjadi seperti pabrik ajaibStrings.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 menggunakanequals()
yang membandingkan urutan karakter daripada persamaan referensi objek.sumber
Salah satu cara sederhana untuk memahami perbedaannya adalah di bawah ini: -
output adalah
Jadi String baru () akan selalu membuat instance baru.
sumber
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.
"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.
"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.
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.
sumber
Meskipun terlihat sama dari sudut pandang programmer, ini memiliki dampak kinerja yang besar. Anda ingin selalu menggunakan formulir pertama.
sumber
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
str
titik referensi ke objek yang dibuat di lokasi memori tumpukan.jika Anda ingin
str
referensi ke objek titik yang berisi dalam string konstan pool maka seseorang harus memanggil secara eksplisitstr.intern();
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,
str
titik referensi ke String"world"
hadir di kumpulan Constant.sumber
Saat Anda menyimpan String sebagai
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
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
menggunakan kata kunci baru, objek baru dengan harga yang diberikan dibuat tidak peduli isi kumpulan konstanta String.
sumber