Dizeler Java'da nesnelerdir, öyleyse neden onları oluşturmak için 'yeni' kullanmıyoruz?


107

Normalde newanahtar kelime kullanarak nesneler oluştururuz , örneğin:

Object obj = new Object();

Dizeler nesnelerdir, ancak newonları oluşturmak için kullanmıyoruz :

String str = "Hello World";

Bu neden? İle String yapabilir miyim new?


Ayrıca bu soru üzerinde bir göz atmalısınız stackoverflow.com/questions/456575/java-wrapper-equality-test
değişti

1
Çünkü dize değişmezleri zaten nesnelerdir.
Marquis of Lorne

1
Not new String(...)geniş dizeleri substringing zaman bir uygulama detay atlatmak için kullanılmıştır. Bu Java 7'de düzeltildi ve artık gerekli değil.
Thorbjørn Ravn Andersen

Ben bu gönderinin 100. beğenicisiyim. :)
Mukit09

Yanıtlar:


131

Önceden söylenenlere ek olarak , Java'daki String değişmezleri [yani, benzer "abcd"ancak benzemeyen dizeler new String("abcd")] dahil edilir - bu, "abcd" den her söz ettiğinizde String, yeni bir örnek yerine tek bir örneğe bir referans alacağınız anlamına gelir. her seferinde. Yani sahip olacaksınız:

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

a == b; //True

ama olsaydı

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

o zaman sahip olmak mümkün

a == b; // False

(ve herhangi birinin hatırlatmaya ihtiyacı olması durumunda, her zaman .equals()Dizeleri karşılaştırmak için kullanın ; ==fiziksel eşitlik testleri).

Interning String değişmez değerleri iyidir çünkü bunlar genellikle birden fazla kez kullanılır. Örneğin, (yapmacık) kodu düşünün:

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

Dizelerin interneti olmasaydı, "Sonraki yineleme" nin 10 kez somutlaştırılması gerekirdi, oysa şimdi yalnızca bir kez somutlaştırılacak.


1
String a = new String ("abcd") kullanılması, bellekte benzer içeriğe sahip iki dizenin mevcut olduğu anlamına mı gelir.
değiştirildi

1
Doğru - derleyici böyle bir String'in zaten staj yapılıp yapılmadığını kontrol etmeyecektir (gerçi bunu kesinlikle yazabilirsiniz).
danben

evet, bu optimizasyon mümkündür çünkü dizeler değişmezdir ve bu nedenle sorunsuz bir şekilde paylaşılabilir. paylaşılan "asdf" işleme, "Flyweight" tasarım modelinin bir uygulamasıdır.
manuel aldana

Hiç kimse bunun mümkün olmadığını, sadece garanti olmadığını söylemişti. Bu sizin olumsuz oyunuz muydu?
danben

"== Nesne eşitliği testleri" ile neyi kastediyorsunuz? Bu bana doğru görünmüyor, ama belki de göründüğünden farklı bir şey kastettiniz.
Dawood ibn Kareem

32

Dizeler Java'da "özel" nesnelerdir. Java tasarımcıları, Dizelerin o kadar sık ​​kullanıldığına akıllıca karar verdiler ve kendi sözdizimlerine ve bir önbelleğe alma stratejisine ihtiyaçları vardı. Bir dizeyi şunu söyleyerek bildirdiğinizde:

String myString = "something";

myString, "bir şey" değerine sahip String nesnesine bir referanstır. Daha sonra beyan ederseniz:

String myOtherString = "something";

Java, myString ve myOtherString'in aynı olduğunu anlayacak kadar akıllıdır ve bunları aynı nesne olarak global bir String tablosunda saklayacaktır. Bunu yapmak için Dizeleri değiştiremeyeceğiniz gerçeğine dayanır. Bu, gerekli bellek miktarını azaltır ve karşılaştırmaları daha hızlı yapabilir.

Onun yerine yazarsan

String myOtherString = new String("something");

Java, myString nesnesinden farklı olarak sizin için yepyeni bir nesne yaratacaktır.


Hey ... dize değişmezleri için bir tür sözdizimsel destek ihtiyacını tanımak için "sonsuz bilgelik" gerektirmez. Hemen hemen her diğer ciddi programlama dili tasarımı bir tür dizge hazır bilgisini destekler.
Stephen C

12
Abartma sersemletmek için azaltıldı, Kaptan :)
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").

Umarım bu birkaç şüpheyi ortadan kaldırır. :)


String d = new String ("def"); // 1 Nesne + "def" Havuza eklenir -> burada "def" yalnızca havuza henüz yoksa eklenir
güney

@southerton Anlamsız. Zaten havuzda. Oraya derleyici tarafından yerleştirildi.
Marquis of Lorne

@EJP neden (e == d) burada yanlıştır? ikisi de havuzda aynı nesneye "def" atıfta bulunuyor, değil mi?
Raja

Dize c = new String ("abc"); // 1 Nesne ... bu ifade doğru mu? "Abc" sabit havuzdan zaten referans alınmışsa, o zaman inter yönteminin kullanımı nedir?
Prashanth Debbadwar

6

Bu bir kısayol. Başlangıçta böyle değildi, ama Java onu değiştirdi.

Bu SSS kısaca bundan bahsediyor. Java Spesifikasyon kılavuzu da bundan bahsediyor. Ama internette bulamıyorum.


2
Kırık bağlantı ve değiştirildiğine dair başka bir kanıtın farkında değilim.
Marquis of Lorne

1
@EJP İşe yarayacaksa hala geri dönüş makinesinde .
Arjan

6

String, birkaç optimizasyona tabidir (daha iyi bir ifade istemek için). String'in ayrıca diğer nesnelerin aksine operatör aşırı yüklemesine (+ operatörü için) sahip olduğunu unutmayın. Yani bu çok özel bir durum.


1
+ Aslında bir StringBuilder.append (..) çağrısına çevrilen bir operatördür.
viskisierra

5

Gereksiz nesneler oluşturmaktan kaçınmak için genellikle String değişmezlerini kullanırız. String nesnesini oluşturmak için new operatörü kullanırsak, her seferinde yeni bir nesne oluşturacaktır.

Misal:

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

Hafızadaki yukarıdaki kod için:

görüntü açıklamasını buraya girin


2

Java'da Dizeler, yalnızca Dizeler için geçerli olan birçok kurala sahip özel bir durumdur. Çift tırnak, derleyicinin bir String nesnesi oluşturmasına neden olur. String nesneleri değişmez olduğundan, bu, derleyicinin birden çok dizeyi staj yapmasına ve daha büyük bir dize havuzu oluşturmasına izin verir. İki özdeş String sabiti her zaman aynı nesne referansına sahip olacaktır. Durumun böyle olmasını istemiyorsanız, yeni String ("") kullanabilirsiniz ve bu, çalışma zamanında bir String nesnesi oluşturur. İntern () yöntemi eskiden dinamik olarak oluşturulan dizelerin dize arama tablosuna göre kontrol edilmesine neden olmak için yaygındı. Bir dizede bir dizeye dahil edildikten sonra, nesne referansı standart String örneğini gösterecektir.

    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

Sınıf yükleyici bir sınıfı yüklediğinde, tüm String sabitleri String havuzuna eklenir.


"Çift tırnak, derleyicinin bir String nesnesi oluşturmasına neden olur." az değer verilen yorum
csguy

0

Sözdizimsel şeker.

String s = new String("ABC");

sözdizimi hala mevcuttur.


1
Bu tam olarak doğru değil. s = new String ("ABC") size s = "ABC" ile aynı sonuçları vermeyecektir. Danben'in yorumuna bakın.
Steve B.

2
Ayrıca, biraz ironik bir şekilde, ilk önce "ABC" satırını temsil eden bir String örneği yaratacak ve sonra bunu yapıcı çağrısına bir argüman olarak iletecek ve bu da aynı değerde bir String döndürür.
Andrzej Doyle

1
Bu yapıcı için geçerli kullanım durumu , orijinal String'den String small = new String(huge.substring(int, int));büyük temelleri geri dönüştürmenize olanak tanır . char[]huge
Pascal Thivent

1
@PascalThivent evet ama artık Java 8 ile değil. Artık dizileri paylaşmıyor (G1 ile otomatik dize tekilleştirme veya yaklaşan dize sıkıştırması gibi diğer optimizasyonlara hazırlık olarak).
Eckes

@AndrzejDoyle Doğru değil. Derleyici, değişmez değer için nesneyi oluşturur.
Marquis of Lorne

0

Hala kullanabilirsiniz new String("string"), ancak dizge değişmezleri olmadan yeni dizeler oluşturmak daha zor olacaktır ... karakter dizileri veya baytlar kullanmanız gerekir :-) Dize değişmezleri bir ek özelliğe sahiptir: herhangi bir sınıf noktasından aynı dizeye kadar tüm aynı dize değişmezleri örnek (staj yapıyorlar).


0

Değişmez (tırnak işaretlerindeki karakterler), host sınıfı yüklendiğinde zaten oluşturulmuş bir String nesnesi olduğundan, yeni bir dizeye neredeyse hiç gerek yoktur. Bir literal ve don üzerinde metotları çağırmak tamamen yasaldır, ana ayrım, literallerin sağladığı kolaylıktır. Bir dizi karakter oluşturup, karakterle doldurup yeni bir String (karakter dizisi) yapmamız gerekirse, bu büyük bir acı ve kayıp olur.


0

İle yeni bir String oluşturmaktan çekinmeyin

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

Olağan gösterim s = "new String";, aşağı yukarı uygun bir kısayoldur - bu , denklem için uygun olan Dizelere gerçekten ihtiyaç duyduğunuz oldukça nadir durumlar dışında performans nedenleriyle kullanılmalıdır.

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

DÜZENLE

Yorum yanıt olarak: Bu edilmiş değil o, Kendisine teze bir tavsiye ama sadece bir tek bir doğrudan yanıt olması amaçlanmıştır biz 'yeni' anahtar kelimesini kullanmayın basitçe doğru değildir Strings için. Umarım bu düzenleme (yukarıdakiler dahil) bunu biraz açıklığa kavuşturur. BTW - SO ile ilgili yukarıdaki soruya birkaç iyi ve çok daha iyi cevap var.


4
-1 - Kötü tavsiye. new String(...)Uygulamanız farklı bir kimliğe sahip bir Dize oluşturmanızı GEREKTİRMEZSE , kullanmakta "kendinizi özgür hissetmemelisiniz" .
Stephen C

1
Bunu biliyorum. Açıklama için gönderiyi düzenledi.
Andreas Dolk

0

Değişmez havuz, anahtar kelime kullanılmadan oluşturulmuş tüm Dizeleri içerir new.

Bir fark var: Yeni referansı olmayan dize, String değişmez havuzunda saklanır ve yeni ile String, yığın belleğinde olduklarını söyler.

Yeni ile dizgi, tıpkı diğer nesneler gibi bellekte başka yerdedir.


0

Çünkü String, java'da değişmez bir sınıftır.

Şimdi neden değişmez? String değişmez olduğundan, birden fazla evre arasında paylaşılabilir ve String işlemini harici olarak senkronize etmemize gerek yoktur. As String, sınıf yükleme mekanizmasında da kullanılır. Yani String değiştirilebilir olsaydı java.io.writer abc.xyz.mywriter olarak değiştirilebilirdi


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");

Çıktı:

Doğru

İki ayrı nesne oluşturdum, her ikisinin de bir alanı (ref) 'Ad' var. Yani bu durumda bile "Jan Peter" paylaşılıyor, java'nın nasıl işlediğini anlıyorsam ..


0

StringPool, javada Hashmap kullanılarak gerçeklenir. Her zaman yeni bir anahtar kelimeyle oluşturuyorsak, String Pool'da arama yapmaz ve onun için yeni bir hafıza yaratırsak, bu daha sonra ihtiyaç duyulabilir, eğer bellek yoğun bir işlemimiz varsa ve performansı etkileyecek tüm dizeleri yeni anahtar kelimeyle oluşturuyorsak uygulamamızın. Bu nedenle, dizge oluşturmak için yeni anahtar sözcükler kullanmamanız tavsiye edilir, çünkü o zaman yalnızca Dize havuzuna gidecek ve bu da bir Hashmap olacaktır, (bellek kaydedildi, yeni anahtar sözcükle oluşturulmuş çok sayıda dizgimiz olup olmadığını düşünün) burada saklanacak ve dizge zaten mevcutsa başvurusu (genellikle Yığın belleğinde bulunur) yeni oluşturulan dizeye döndürülür. Yani performansı artırmak için yapılır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.