String sınıfı + operatörünü nasıl geçersiz kılar?


129

String bir sınıfken Java'da neden + operatörüyle Dizeler ekleyebiliyorsunuz? Kodda String.javabu operatör için herhangi bir uygulama bulamadım. Bu kavram nesne yönelimini ihlal ediyor mu?


21
Artı ( +) operatörü Java'nın dil özelliğidir.
adatapost

18
Hepsi derleyicinin sihri. Java'da operatör aşırı yükleme yapamazsınız.
Lion

18
Bence garip olan şey, String'in dil dışında (java.lang.String'de) bir kütüphane olarak uygulanması , ancak dil içinde belirli bir desteğe sahip olmasıdır . Bu doğru değil.
13ren


@ 13ren yanılıyorsun. String, dil anlamına gelen java.lang sınıfının bir parçasıdır - java dili !!! Bu paketteki tüm sınıflar özeldir. Bunları kullanmak için java.lang dosyasını içe aktarmanız gerekmediğine dikkat edin.

Yanıtlar:


156

Java'da aşağıdaki basit ifadelere bakalım

int x=15;
String temp="x = "+x;

Derleyici dahili "x = "+x;olarak bir türe dönüştürür ve tamsayıyı dizeye "eklemek" için StringBuilderkullanır .append(int).

5.1.11. Dize Dönüşümü

Herhangi bir tür, dize dönüşümüyle Dize türüne dönüştürülebilir.

İlkel tip T'nin bir x değeri, uygun bir sınıf örneği oluşturma ifadesine (§15.9) bağımsız değişken olarak verilerek önce bir referans değerine dönüştürülür:

  • T boole ise, yeni Boole (x) kullanın.
  • T bir karakter ise, yeni Karakter (x) kullanın.
  • T bayt, kısa veya int ise, yeni Tamsayı (x) kullanın.
  • T uzunsa, yeni Long (x) kullanın.
  • T float ise, yeni Float (x) kullanın.
  • T çift ise, yeni Double (x) kullanın.

Bu referans değeri daha sonra dize dönüşümüyle String türüne dönüştürülür.

Şimdi sadece referans değerlerin dikkate alınması gerekiyor:

  • Başvuru boş ise, "null" dizesine dönüştürülür (dört ASCII karakteri n, u, l, l).
  • Aksi takdirde, dönüştürme, başvurulan nesnenin toString yönteminin argümansız olarak çağrılmasıyla gerçekleştirilir; ancak toString yöntemini çağırmanın sonucu null ise, bunun yerine "null" dizesi kullanılır.

ToString yöntemi, ilkel sınıf Object (§4.3.2) tarafından tanımlanır. Boolean, Character, Integer, Long, Float, Double ve String gibi birçok sınıf bunu geçersiz kılar.

Dizi dönüştürme bağlamının ayrıntıları için §5.4'e bakın.

15.18.1.

Dize Birleştirme Optimizasyonu: Bir uygulama, bir ara String nesnesi oluşturmaktan ve sonra atmaktan kaçınmak için tek adımda dönüştürme ve birleştirme yapmayı seçebilir. Yinelenen dize birleştirme performansını artırmak için, bir Java derleyicisi, bir ifadenin değerlendirilmesiyle oluşturulan ara String nesnelerinin sayısını azaltmak için StringBuffer sınıfını veya benzer bir tekniği kullanabilir.

İlkel türler için, bir uygulama, doğrudan bir ilkel türden bir dizeye dönüştürerek bir sarıcı nesnenin yaratılmasını optimize edebilir.

Optimize edilmiş sürüm aslında önce tam sarılmış bir Dize dönüşümü yapmayacaktır.

Bu, derleyici tarafından kullanılan en iyi duruma getirilmiş sürümün iyi bir örneğidir, ancak bir ilkel dönüştürülmeden derleyicinin şeyleri arka planda bir StringBuilder'a dönüştürdüğünü görebilirsiniz:

http://caprazzi.net/posts/java-bytecode-string-concatenation-and-stringbuilder/


Bu java kodu:

public static void main(String[] args) {
    String cip = "cip";
    String ciop = "ciop";
    String plus = cip + ciop;
    String build = new StringBuilder(cip).append(ciop).toString();
}

Bunu üretir - iki birleştirme stilinin nasıl aynı bayt koduna yol açtığını görün:

 L0
    LINENUMBER 23 L0
    LDC "cip"
    ASTORE 1
   L1
    LINENUMBER 24 L1
    LDC "ciop"
    ASTORE 2

   // cip + ciop

   L2
    LINENUMBER 25 L2

    NEW java/lang/StringBuilder
    DUP
    ALOAD 1
    INVOKESTATIC java/lang/String.valueOf(Ljava/lang/Object;)Ljava/lang/String;
    INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V
    ALOAD 2
    INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
    INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String;

    ASTORE 3

    // new StringBuilder(cip).append(ciop).toString()

   L3
    LINENUMBER 26 L3

    NEW java/lang/StringBuilder
    DUP
    ALOAD 1
    INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V
    ALOAD 2
    INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
    INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String;

    ASTORE 4
   L4
    LINENUMBER 27 L4
    RETURN

Yukarıdaki örneğe ve verilen örnekteki kaynak koduna dayalı bayt kodunun nasıl oluşturulduğuna bakıldığında, derleyicinin aşağıdaki ifadeyi dahili olarak dönüştürdüğünü fark edebileceksiniz.

cip+ciop; 

içine

new StringBuilder(cip).append(ciop).toString();

Başka bir deyişle, +dizge birleştirme işlemindeki operatör , daha ayrıntılı StringBuilderdeyim için etkili bir kısaltmadır .


3
Çok teşekkürler, jvm bayt kodlarına aşina değilim ama String plus = cip + ciop için kod oluşturuldu; ve String build = new StringBuilder (cip) .append (ciop) .toString (); aynı. ve sorum şu ki bu işlem nesne yönelimini ihlal ediyor mu?
Pooya

7
Hayır değil. Operatör aşırı yüklemesinin (C ++ ve bazı dillerde olduğu gibi) bazı dezavantajları vardır ve Java tasarımcıları bunun biraz kafa karıştırıcı bir kavram olduğunu düşünerek Java'dan çıkardılar. Bana göre, nesne yönelimli bir dil, Java'nın sahip olduğu temel kalıtım, çok biçimlilik ve kapsülleme kavramlarına sahip olmalıdır.
Lion

2
evet, ancak bu operatörün String sınıfı için aşırı yüklendiğini düşünüyorum
Pooya

3
Evet, Java'da String tipinin birleştirilmesi için operatör aşırı yüklemesi kullanılır ancak kendi operatörünüzü tanımlayamazsınız (C ++, C # ve diğer bazı dillerde olduğu gibi).
Lion

5
@Pooya: aslında "int / int" ve "int / float" zaten operatör aşırı yüklemesi, yani C bile buna sahip. Ancak C (ve Java) 'nın sahip olmadığı şey, kullanıcı tanımlı operatör aşırı yüklemesidir: bir operatörün (hem C hem de Java'da) kullanılabileceği farklı yolları tanımlayan tek şey dil tanımıdır (ve ayrım, derleyici). C ++, kullanıcı tanımlı operatör aşırı yüklemesine izin vermesi bakımından farklılık gösterir (bu genellikle basitçe "operatör aşırı yükleme" olarak adlandırılır).
Joachim Sauer

27

+Operatörün işlenenlerini kontrol eden Java derleyici özelliğidir . Ve işlenenlere göre bayt kodunu üretir:

  • String için, dizeleri birleştirmek için kod üretir.
  • Numbers için, numara eklemek için kod üretir.

Java spesifikasyonunun söylediği şu :

+ Ve -operatörlerine eklemeli operatörler denir. AdditiveExpression: MultiplicativeExpression AdditiveExpression + MultiplicativeExpression AdditiveExpression - MultiplicativeExpression

Katkı operatörleri aynı önceliğe sahiptir ve sözdizimsel olarak sol ilişkilidir (soldan sağa gruplanırlar). Bir +operatörün işlenenlerinden birinin türü ise String, işlem dize birleştirme işlemidir.

Aksi takdirde, +operatörün işlenenlerinden her birinin türü, ilkel bir sayısal türe dönüştürülebilir (§5.1.8) bir tür olmalıdır, yoksa bir derleme zamanı hatası oluşur.

Her durumda, ikili -operatörün işlenenlerinden her birinin türü, ilkel bir sayısal türe dönüştürülebilir (§5.1.8) bir tür olmalıdır, yoksa bir derleme zamanı hatası oluşur.


7
Spesifikasyondan alınan alıntı bu soruyla hiç alakalı değil.
Ernest Friedman-Hill

Bu, "Bir + operatörünün işlenenlerinden birinin türü String ise, işlem dize birleştirmedir. Aksi takdirde, + operatörünün her bir işlenen türü dönüştürülebilir bir tür olmalıdır (§5.1.8 ) ilkel bir sayısal türe dönüşür veya derleme zamanı hatası oluşur ". Lütfen bunun neden alakalı olmadığını söyler misiniz?
Ramesh PVK

7
Nasıl uygulandığı hakkında hiçbir şey söylemiyor, ki bu soru. Posterin zaten bu özelliğin var olduğunu anladığını düşünüyorum.
Ernest Friedman-Hill

14

String sınıfı + operatörünü nasıl geçersiz kılar?

Öyle değil. Derleyici yapar. Kesin olarak, derleyici String işlenenleri için + operatörünü aşırı yükler .


6

Öncelikle (+) aşırı yüklenmiştir, geçersiz kılınmamıştır

Java dili, Java Strings nesneleri için aşırı yüklenmiş olan dizi birleştirme operatörü (+) için özel destek sağlar.

  1. Sol taraftaki işlenen String ise birleştirme olarak çalışır.

  2. Sol taraftaki işlenen Tamsayı ise toplama operatörü olarak çalışır


3
(2) Sol işlenen bir Tamsayı ise otomatik olarak kutudan çıkarılır intve bu durumda normal Java kuralları uygulanır.
Marquis of Lorne

2
Alıntının altında verilen iki kural yanlıştır: Bence bunlar: iki ilkel (veya kutulanamayan sınıflar) = toplama; en az bir dize = bitiştirme
mwfearnley

4

Java dili, dizgi birleştirme operatörü (+) ve diğer nesnelerin dizelere dönüştürülmesi için özel destek sağlar. Dize birleştirme, StringBuilder(veya StringBuffer) sınıfı ve appendyöntemi aracılığıyla uygulanır .


4

+Operatörün uygulandığında anlamı, Stringherkesin zaten yazdığı gibi, dil tarafından tanımlanır. Bunu yeterince ikna edici bulmadığınız için şunu düşünün:

İnts, float ve double'ların hepsi farklı ikili temsillere sahiptir ve bu nedenle iki tamsayı eklemek, bit manipülasyonu açısından iki kayan nokta eklemekten farklı bir işlemdir: İnts için parça parça ekleyebilir, biraz taşıyabilir ve taşmayı kontrol edebilirsiniz; float'lar için mantisler ve üslerle ayrı ayrı ilgilenmelisiniz.

Bu nedenle, prensip olarak, "ekleme", "eklenen" nesnelerin doğasına bağlıdır. Java bunu Dizeler için olduğu kadar ints ve float'lar için de tanımlar (longs, double, ...)


3

+Operatör genellikle ile değiştirilir StringBuilderderleme sırasında. Konuyla ilgili daha fazla ayrıntı için bu yanıtı kontrol edin .


Durum buysa, StringBuilder'ın herkesin kullanımına açık olmasının herhangi bir nedeni var mı? +Operatörün değiştirmediği durumlar var StringBuildermı?
Cemre

2
Sormak istediğiniz soru, "neden + operatörü kamu kullanımı için var?", Çünkü buradaki iğrenç şey budur. Diğer sorunuza gelince, tam olarak bilmiyorum ama sanırım böyle bir durum yok.
Akrep

Yalnızca iki öğe varsa derleyici bunun yerine concat () kullanabilir. Ayrıca derleyici, programcı uzun iç içe / döngülü kodda dize oluştururken concat () öğesini StringBuilder ile değiştirmeyi başaramaz (veya birden çok StringBuilders kullanır ve bunları bir araya getirir) - tek, açık StringBuilder kullanmak performans için daha iyi olacaktır.
user158037
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.