String adalah objek di Java, jadi mengapa kita tidak menggunakan 'baru' untuk membuatnya?

104

Kami biasanya membuat objek menggunakan newkata kunci, seperti:

Object obj = new Object();

String adalah objek, namun kami tidak menggunakannya newuntuk membuatnya:

String str = "Hello World";

Kenapa ini? Bisakah saya membuat String dengan new?

giri
sumber
Anda juga harus melihat pertanyaan ini stackoverflow.com/questions/456575/java-wrapper-equality-test
diubah pada
1
Karena literal string sudah menjadi objek.
Marquis dari Lorne
1
Catatan yang new String(...)telah digunakan untuk menghindari detail implementasi saat membuat substring string besar. Ini telah diperbaiki di Java 7 dan tidak diperlukan lagi.
Thorbjørn Ravn Andersen
Saya liker ke-100 dari posting ini. :)
Mukit09

Jawaban:

130

Selain apa yang telah dikatakan, String literal [yaitu, String suka "abcd"tapi tidak suka new String("abcd")] di Java disimpan - ini berarti bahwa setiap kali Anda merujuk ke "abcd", Anda mendapatkan referensi ke satu Stringinstance, bukan yang baru setiap kali. Jadi, Anda akan memiliki:

String a = "abcd";
String b = "abcd";

a == b; //True

tetapi jika Anda punya

String a = new String("abcd");
String b = new String("abcd");

maka mungkin untuk memilikinya

a == b; // False

(dan jika ada yang perlu diingatkan, selalu gunakan .equals()untuk membandingkan String; ==tes untuk persamaan fisik).

Literal String Interning bagus karena sering digunakan lebih dari sekali. Misalnya, perhatikan kode (dibuat-buat):

for (int i = 0; i < 10; i++) {
  System.out.println("Next iteration");
}

Jika kita tidak memiliki string internal, "Iterasi berikutnya" perlu dibuat 10 kali, sedangkan sekarang hanya akan dibuat sekali.

danben
sumber
1
Dengan menggunakan String a = new String ("abcd"), artinya ada dua string dengan konten serupa yang ada di memori.
diubah
1
Benar - kompiler tidak perlu memeriksa untuk melihat apakah String seperti itu telah diinternir (meskipun Anda pasti bisa menulis yang melakukannya).
danben
ya, pengoptimalan ini dimungkinkan karena string tidak dapat diubah dan oleh karena itu dapat dibagikan tanpa masalah. penanganan "asdf" bersama merupakan implementasi dari pola desain 'Kelas Terbang'.
manuel aldana
Tidak ada yang mengatakan bahwa itu tidak mungkin, hanya saja itu tidak dijamin. Apakah itu suara negatif Anda?
danben
Apa yang Anda maksud dengan "== tes untuk persamaan objek"? Ini tampaknya tidak benar bagi saya, tetapi mungkin maksud Anda adalah sesuatu yang berbeda dari apa yang tampaknya berarti.
Dawood ibn Kareem
32

String adalah objek "khusus" di Java. Desainer Java dengan bijak memutuskan bahwa String digunakan begitu sering sehingga mereka membutuhkan sintaksisnya sendiri serta strategi caching. Saat Anda mendeklarasikan string dengan mengatakan:

String myString = "something";

myString adalah referensi ke objek String dengan nilai "sesuatu". Jika Anda kemudian menyatakan:

String myOtherString = "something";

Java cukup pintar untuk mengetahui bahwa myString dan myOtherString adalah sama dan akan menyimpannya dalam tabel String global sebagai objek yang sama. Ini bergantung pada fakta bahwa Anda tidak dapat memodifikasi Strings untuk melakukan ini. Ini menurunkan jumlah memori yang dibutuhkan dan dapat membuat perbandingan lebih cepat.

Sebaliknya, jika Anda menulis

String myOtherString = new String("something");

Java akan membuat objek baru untuk Anda, berbeda dari objek myString.

Jamie McCrindle
sumber
Hei ... tidak membutuhkan "kebijaksanaan tak terbatas" untuk mengenali kebutuhan akan semacam dukungan sintaksis untuk string literal. Hampir setiap desain bahasa pemrograman serius lainnya mendukung beberapa jenis string literal.
Stephen C
12
Hiperbola telah dikurangi menjadi pingsan, Kapten :)
Jamie McCrindle
16
String a = "abc"; // 1 Object: "abc" added to pool

String b = "abc"; // 0 Object: because it is already in the pool

String c = new String("abc"); // 1 Object

String d = new String("def"); // 1 Object + "def" is added to the Pool

String e = d.intern(); // (e==d) is "false" because e refers to the String in pool

String f = e.intern(); // (f==e) is "true" 

//Total Objects: 4 ("abc", c, d, "def").

Semoga ini menghilangkan beberapa keraguan. :)

Crocode
sumber
String d = String baru ("def"); // 1 Object + "def" ditambahkan ke Pool -> di sini "def" akan ditambahkan ke pool hanya jika belum ada
southerton
@OutherlyTidak ada artinya. Itu sudah ada di kolam. Itu ditempatkan di sana oleh kompiler.
Marquis dari Lorne
@EJP mengapa (e == d) salah di sini? keduanya mengacu pada objek yang sama "def" di kumpulan, bukan?
Raja
String c = String baru ("abc"); // 1 Object ... apakah pernyataan ini benar? Jika "abc" sudah direferensikan dari kumpulan konstan lalu apa gunanya metode inter?
Prashanth Debbadwar
6

Itu jalan pintas. Awalnya tidak seperti itu, tetapi Java mengubahnya.

FAQ ini membahasnya secara singkat. Panduan Spesifikasi Java membicarakannya juga. Tetapi saya tidak dapat menemukannya secara online.

Malfist
sumber
2
Tautan rusak, dan saya tidak mengetahui adanya bukti lain bahwa itu pernah berubah.
Marquis dari Lorne
1
@EJP Ini masih dalam mesin wayback jika itu berguna.
Arjan
6

String tunduk pada beberapa optimisasi (karena menginginkan frase yang lebih baik). Perhatikan bahwa String juga memiliki operator overloading (untuk + operator) - tidak seperti objek lainnya. Jadi ini kasus yang sangat khusus.

Brian Agnew
sumber
1
Tanda + sebenarnya adalah operator yang diterjemahkan menjadi panggilan StringBuilder.append (..).
whiskysierra
5

Kami biasanya menggunakan literal String untuk menghindari membuat objek yang tidak perlu. Jika kita menggunakan operator baru untuk membuat objek String, maka itu akan membuat objek baru setiap saat.

Contoh:

String s1=“Hello“;
String s2=“Hello“;
String s3= new String(“Hello“);
String s4= new String(“Hello“);

Untuk kode di atas di memori:

masukkan deskripsi gambar di sini

Joby Wilson Mathews
sumber
2

Di Java, String adalah kasus khusus, dengan banyak aturan yang hanya berlaku untuk String. Tanda kutip ganda menyebabkan compiler membuat objek String. Karena objek String tidak dapat diubah, hal ini memungkinkan kompilator untuk menyimpan beberapa string, dan membangun kumpulan string yang lebih besar. Dua konstanta String yang identik akan selalu memiliki referensi objek yang sama. Jika Anda tidak ingin hal ini terjadi, Anda dapat menggunakan String baru (""), dan itu akan membuat objek String pada waktu proses. Metode intern () digunakan untuk umum, untuk menyebabkan string yang dibuat secara dinamis diperiksa terhadap tabel pencarian string. Setelah string dimasukkan, referensi objek akan mengarah ke instance String kanonik.

    String a = "foo";
    String b = "foo";
    System.out.println(a == b); // true
    String c = new String(a);
    System.out.println(a == c); // false
    c = c.intern();
    System.out.println(a == c); // true

Saat classloader memuat kelas, semua konstanta String ditambahkan ke kumpulan String.

brianegge.dll
sumber
"Tanda kutip ganda menyebabkan kompilator membuat objek String." komentar undervalued
csguy
0

Gula sintaksis. Itu

String s = new String("ABC");

sintaks masih tersedia.

Seva Alekseyev
sumber
1
Ini kurang tepat. s = new String ("ABC") tidak akan memberikan hasil yang sama seperti s = "ABC". Lihat komentar danben.
Steve B.
2
Juga, agak ironis, pertama-tama akan membuat instance String yang mewakili "ABC" inline - dan kemudian meneruskannya sebagai argumen ke panggilan konstruktor yang akan membuat kembalian String dengan nilai identik.
Andrzej Doyle
1
Kasus penggunaan yang valid untuk konstruktor ini adalah String small = new String(huge.substring(int, int));, yang memungkinkan Anda mendaur ulang dasar besar char[]dari hugeString asli .
Pascal Thivent
1
@PascalThivent ya, tetapi tidak lagi dengan Java 8. Ini tidak lagi berbagi array (dalam persiapan untuk pengoptimalan lain seperti deduplikasi string otomatis dengan G1 atau kompresi string yang akan datang).
eckes
@Andoye Tidak benar. Kompilator membuat objek untuk literal.
Marquis dari Lorne
0

Anda masih dapat menggunakan new String("string"), tetapi akan lebih sulit untuk membuat string baru tanpa literal string ... Anda harus menggunakan array karakter atau byte :-) Literal string memiliki satu properti tambahan: semua literal string yang sama dari titik kelas mana pun ke string yang sama Misalnya (mereka diinternir).

Peter Štibraný
sumber
0

Hampir tidak perlu lagi string baru karena literal (karakter dalam tanda kutip) sudah menjadi objek String yang dibuat saat kelas host dimuat. Adalah legal untuk menggunakan metode literal dan don, perbedaan utamanya adalah kenyamanan yang diberikan oleh literal. Ini akan menjadi rasa sakit dan pemborosan waktu jika kita harus membuat array karakter dan mengisinya char demi char dan mereka melakukan String baru (char array).

mP.
sumber
0

Jangan ragu untuk membuat String baru dengan

String s = new String("I'm a new String");

Notasi biasa s = "new String";kurang lebih merupakan jalan pintas yang nyaman - yang harus digunakan untuk alasan performa kecuali untuk kasus yang sangat jarang terjadi, di mana Anda benar - benar membutuhkan String yang memenuhi syarat untuk persamaan tersebut

(string1.equals(string2)) && !(string1 == string2)

EDIT

Menanggapi komentar: ini tidak dimaksudkan sebagai saran tetapi hanya tanggapan langsung terhadap tesis penanya, bahwa kami tidak menggunakan kata kunci 'baru' untuk String, yang sama sekali tidak benar. Semoga hasil edit ini (termasuk di atas) sedikit menjelaskan hal ini. BTW - ada beberapa jawaban yang baik dan jauh lebih baik untuk pertanyaan di atas tentang SO.

Andreas Dolk
sumber
4
-1 - Saran yang buruk. Anda TIDAK boleh "merasa bebas" untuk menggunakan new String(...)KECUALI aplikasi Anda MEMBUTUHKAN Anda untuk membuat String dengan identitas yang berbeda.
Stephen C
1
Saya tahu itu. Mengedit postingan untuk klarifikasi.
Andreas Dolk
0

Kumpulan literal berisi String apa pun yang dibuat tanpa menggunakan kata kunci new.

Ada perbedaan: String tanpa referensi baru disimpan di kolam literal String dan String dengan yang baru mengatakan bahwa mereka ada di memori heap.

String dengan new ada di tempat lain di memori sama seperti objek lainnya.

lavina
sumber
0

Karena String adalah kelas yang tidak dapat diubah di java.

Sekarang mengapa itu tidak bisa diubah? Karena String tidak dapat diubah sehingga dapat dibagikan di antara beberapa utas dan kami tidak perlu menyinkronkan operasi String secara eksternal. As String juga digunakan dalam mekanisme pemuatan kelas. Jadi jika String bisa berubah maka java.io.writer bisa saja diubah menjadi abc.xyz.mywriter

Mr37037
sumber
0
TString obj1 = new TString("Jan Peter");                
TString obj2 = new TString("Jan Peter");                    

if (obj1.Name == obj2.Name)                 
    System.out.println("True");
else                
    System.out.println("False");

Keluaran:

Benar

Saya membuat dua objek terpisah, keduanya memiliki bidang (ref) 'Nama'. Begitu pun dalam hal ini "Jan Peter" di-share, jika saya mengerti cara transaksi java ..

Pete Del Fina
sumber
0

Nah, StringPool diimplementasikan menggunakan The Hashmap di java. Jika kita selalu membuat dengan kata kunci baru itu tidak mencari di String Pool dan membuat memori baru untuknya yang mungkin diperlukan nanti jika kita menjalankan operasi intensif memori dan jika kita membuat semua string dengan kata kunci baru yang akan mempengaruhi kinerja dari aplikasi kita. Jadi disarankan untuk tidak menggunakan kata kunci baru untuk membuat string karena hanya itu yang akan masuk ke kolam String yang pada gilirannya adalah Hashmap, (memori disimpan, bayangkan jika kita memiliki banyak string yang dibuat dengan kata kunci baru) di sini itu akan disimpan dan jika string sudah ada, referensinya (yang biasanya berada di memori Stack) akan dikembalikan ke string yang baru dibuat. Jadi itu dilakukan untuk meningkatkan kinerja.

Vinay Shrivastava
sumber