Neden == işleç dizgisi değer karşılaştırması Java’ya gelmedi?


50

Her yetkili Java programcısı, == yerine dize karşılaştırmak için String.equals () kullanmanız gerektiğini bilir; çünkü == referans eşitliği için denetler.

Dizelerle uğraşırken, çoğu zaman referans eşitliği yerine değer eşitliğini kontrol ediyorum. Bana göre dize değerleri sadece == kullanarak karşılaştırılabilirse, dil sezgisel olarak karşılaştırılabilir.

Karşılaştırma olarak, C # 'ın == işleci s dizgisi için değer eşitliği olup olmadığını kontrol eder . Ve gerçekten referans eşitliğini kontrol etmeniz gerekiyorsa, String.ReferenceEquals öğesini kullanabilirsiniz.

Bir başka önemli nokta, Tellerin değişmez olmasıdır, bu yüzden bu özelliğe izin vererek yapılacak hiçbir zarar yoktur.

Bunun Java’da uygulanmamasının belirli bir nedeni var mı?


12
==Nesne eşitliği ve eqreferans eşitliği olan Scala'ya bakmak isteyebilirsiniz ( ofps.oreilly.com/titles/9780596155957/… ).
Giorgio

Tıpkı bir not gibi, ve bu size yardımcı olmayabilir, ama hatırladığım kadarıyla, dize değişmezlerini '==' ile karşılaştırabilirsiniz
Kgrover

10
@Kgrover: yapabilirsiniz, ancak bu sadece referans eşitliği için uygun bir yan ürün ve Java'nın eşleştirme hazırlayıcılarını aynı nesneye referanslar olarak nasıl agresif bir şekilde optimize ettiğini gösterir. Başka bir deyişle, işe yarıyor ama yanlış sebeplerden dolayı.
tdammers

1
@aviv ==operatörü yalnızca eşleştiren Equalseğer ==operatör bu şekilde hayata geçirildi. İçin varsayılan davranış ==aynıdır ReferenceEquals(aslında, ReferenceEqualsnesne versiyonuyla tanımlanır ==)
Patrick Huizinga

3
Diğer birçok senaryoda çok anlamlı olan tasarım kararlarının bir sonucudur. Ancak bunu biliyor gibi görünüyorsunuz ve bunu zaten soruyorsanız, sorunuzu yanıtlamaya mecbur olduğumu hissediyorum: Neden String referans karşılaştırması için bir kullanım örneği olmak zorunda?
Jacob Raihle

Yanıtlar:


90

Sanırım sadece tutarlılık ya da "en az şaşkınlık ilkesi". Dize bir nesnedir, diğer nesnelerden farklı şekilde muamele görmesi şaşırtıcı olurdu.

Java'nın ortaya çıktığı tarihte (~ 1995), yalnızca bir şeye sahip Stringolmak, dizeleri boş sonlandırılmış diziler olarak temsil etmeye alışmış çoğu programcı için tamamen lüksdü. String'nin davranışı şimdi o zamanlar olduğu şeydi ve bu iyi; davranışı sonradan inceleyerek değiştirmek, çalışma programlarında şaşırtıcı ve istenmeyen etkilere neden olabilir.

Bir yan not olarak, String.intern()dizgenin kanonik (interned) bir gösterimini elde etmek için kullanabilirsiniz , bundan sonra karşılaştırmalar yapılabilir ==. Interning biraz zaman alıyor, ancak ondan sonra karşılaştırmalar çok hızlı olacak.

Ekleme: Bazı cevapların aksine, operatörün aşırı yüklenmesini desteklemekle ilgili değildir . +Operatörü (birleştirme) çalışır StringJava aşırı operatörü desteklemiyor olsa bile s; basitçe derleyicide çözülen özel bir durum olarak ele alınır StringBuilder.append(). Benzer şekilde, ==özel bir durum olarak ele alınabilirdi.

Öyleyse neden özel durumla hayretler içinde +değil ==? Çünkü +sadece gelmez derlemek olmayan uygulandığında Stringo hızla belirgin yüzden nesneler. Farklı davranış , ==çok daha az belirgin ve dolayısıyla size çarptığında çok daha şaşırtıcı olurdu.


8
Özel durumlar şaşkınlık yaratıyor.
Blrfl

17
Teller 1995’te lüks mü? Gerçekten mi?? Bilgisayar dillerinin geçmişine bakın. O sırada bir tür dize bulunan dillerin sayısı olmayanlara göre çok daha fazla olurdu. C'den başka kaç dil var ve soyundan gelenler boş sonlandırılmış dizileri kullandı?
WarrenT

14
@WarrenT: Elbette, bazı (en fazla değilse) dilde bazı tipte ipler vardı, ancak Unicode yetenekli, çöp toplayan dizelerin 1995'te bir yenilik olduğunu düşünüyorum. Örneğin, Python 2000 yılı sürüm 2.0, Unicode dizgilerini tanıttı. Değişmezliği seçmek aynı zamanda tartışmalı bir seçimdi.
Joonas Pulakka

3
@JoonasPulakka O zaman belki de bunu söylemek için cevabınızı düzenlemelisiniz. Çünkü, durduğu gibi, cevabınızın “toplam lüks” kısmı oldukça yanlış.
svick,

1
Interning'in bir bedeli var: asla dağıtılmayacak bir ip elde edersiniz. (Eh, kendi motorunu kullanıp fırlatabileceğiniz motor kullanmazsan.)
Donal Fellows 19.03:

32

Java'nın yaratıcısı James Gosling bunu Temmuz 2000’de şöyle açıkladı :

C ++ 'ta çok fazla insanın suistimal ettiğini gördüm çünkü operatörün aşırı yüklenmesini oldukça kişisel bir tercih olarak bıraktım. Geçtiğimiz beş ila altı yıl boyunca insanları operatör aşırı yüklemesi konusunda araştırmak için çok zaman harcadım ve bu gerçekten büyüleyici, çünkü toplumu üç parçaya ayırıyorsunuz: Muhtemelen nüfusun yüzde 20 ila 30'u operatörün aşırı yüklendiğini düşünüyor şeytanın doğuşu; Birisi operatör aşırı yüklemesiyle, onları gerçekten zorlayan bir şey yaptı, çünkü liste eklemek için + gibi kullandılar ve hayatı gerçekten çok kafa karıştırıcı hale getiriyorlardı. Bu sorunun birçoğu, mantıklı bir şekilde aşırı yükleyebileceğiniz yalnızca yarım düzine operatörün mevcut olmasından kaynaklanıyor ve yine de insanların tanımlamak isteyeceği binlerce veya milyonlarca operatör var.


50
Ah, evet, eski "sivri uçlu aracı susturmak için izin ver" böylece kâğıtlar kendilerine zarar vermez ".
Blrfl

22
@Blrfl: Bir araç çözdüğünden daha fazla sorun yaratırsa, iyi bir araç değildir. Elbette, bu durumun operatör aşırı yüklenmesinin geçerli olup olmadığına karar verilmesi çok uzun bir tartışmaya dönüşebilir.
Giorgio

15
-1. Bu soruya hiç cevap vermiyor. Java yapar operatör aşırı yüklenmesini var. ==Operatör nesneleri ve ilkel için aşırı yüklü. +Operatör için aşırı byte, short, int, long, float, double, Stringve diğerleri muhtemelen bir kaç unuttum. Aşırı mükemmel mümkün olurdu ==için Stringde.
Jörg W Mittag

10
@Jorg - hayır değil. Kullanıcı seviyesinde kullanıcı aşırı yüklenmesinin tanımlanması mümkün değildir. Derleyicide gerçekten bazı özel durumlar var, ancak bu pek de uygun değil
AZ01

9
@Blrfl: Oafların kendilerini incitmesine aldırış etmiyorum. Kazara beni rahatsız ettiğimde gözlerimi dürttüler.
Jonas

9

Dil içindeki tutarlılık. Farklı davranan bir operatöre sahip olmak programlayıcı için şaşırtıcı olabilir. Java, kullanıcıların operatörleri aşırı yüklemesine izin vermez - bu nedenle referans eşitliği, ==nesneler arasındaki tek makul anlamdır .

Java içinde:

  • Sayısal türler arasında ==sayısal eşitliği karşılaştırır
  • Boole türleri arasında, ==boole eşitliği karşılaştırılır
  • Nesneler arasında ==referans kimliğini karşılaştırır
    • .equals(Object o)Değerleri karşılaştırmak için kullanın

Bu kadar. Basit kural ve ne istediğinizi tanımlamak için basit. Bunların hepsi JLS'nin 15.21. Bölümünde ele alınmıştır . Anlaşılması, uygulanması ve akla gelmesi kolay üç alt bölümden oluşur.

Aşırı yüklenmeye izin== verdikten sonra , tam davranış JLS'ye bakabileceğiniz ve parmağınızı belirli bir öğeye koyabileceğiniz ve "nasıl çalıştığı" diyebileceğiniz bir şey değildir, kodun nedenini anlamak zor olabilir. Kesin davranışı ==bir kullanıcı için şaşırtıcı olabilir. Ne zaman görsen, geri dönüp gerçekte ne anlama geldiğini kontrol etmelisin.

Java, operatörlerin aşırı yüklenmesine izin vermediğinden, temel tanımını geçersiz kılabileceğiniz bir değer eşitliği testine sahip olmanız için bir yol gerekir. Böylece, bu tasarım seçimlerinde zorunlu kılındı. ==Java'da sayısal türler için sayısal, boolean türler için boole eşitliği ve diğer her şey için referans eşitliği ( .equals(Object o)değer eşitliği için ne isterlerse yapamazlar).

Bu, "bu tasarım kararının belirli bir sonucu için bir kullanım davası var mı" meselesi değil, "bu diğer şeyleri kolaylaştıracak bir tasarım kararıdır, bunun bir sonucudur."

String interning , buna böyle bir örnektir. Göre JLS 3.10.5 , tüm dize hazır enterne edilmiştir. Biri üzerine çağırırsa diğer dizeler interneddedir .intern(). Bu "foo" == "foo"doğrudur, String değişmezleri tarafından alınan bellek izini en aza indirgemek için verilen tasarım kararlarının bir sonucudur. Bunun ötesinde, String interning, kullanıcıya biraz maruz kaldığı JVM seviyesinde olan bir şeydir, ancak vakaların çok büyük bir çoğunluğunda, programlayıcıyı ilgilendiren bir şey olmamalıdır (ve programcılar için vaka kullanmayın; Bu özellik dikkate alındığında tasarımcılar için listede yüksek olan bir şey).

İnsanlar bunu gösterecek +ve +=String için aşırı yüklenecek . Ancak bu ne burada ne de orada. Bu ise bu durumda kalır ==dize (ve yalnızca String) için bir anlam değeri eşitliği vardır, biri gerekir farklı referans eşitlik için (yani yalnızca String içinde var) yöntemi. Ayrıca, bu Object'i alan ve ==bir şekilde .equals()davranmayı ve kullanıcıların String için tüm bu yöntemleri özel olarak ele almasını gerektiren başka bir şekilde davranmayı bekleyen yöntemleri gereksiz bir şekilde karmaşıklaştırır .

==Nesneler için tutarlı sözleşme, yalnızca referans eşitliği olması ve değer eşitliği için test etmesi gereken.equals(Object o) tüm nesneler için mevcut olmasıdır . Bunu karmaşık hale getirmek çok fazla şeyi karmaşıklaştırıyor.


cevaplamak için zaman ayırdığınız için teşekkür ederiz. Bu bağlantılı olduğum diğer sorulara harika bir cevap olur. Ne yazık ki, bu bu soru için uygun değil. OP'yi yorumlara dayanan açıklamalarla güncelleyeceğim. Bir dize-kullanıcının dizeleri karşılaştırırken yanlış negatiflere sahip olmak isteyeceği kullanım durumlarını daha fazla arıyorum. Dil bu özelliği tutarlılık olarak sağlıyor, şimdi bir adım daha ileri gitmemizi istiyorum. Belki de bunu yeni dil tasarımcısından düşünüyorum, gerekli mi? (ne yazık ki, hiçbir lang-design.SE)
Anonsage

3
@Ansaj yanlış bir negatif değildir. Aynı nesne değiller. Bütün söylediği bu. Ayrıca Java 8'de new String("foo") == new String("foo")doğru olabileceğini de belirtmeliyim (bkz. String Deduplication ).

1
Dil tasarımına gelince, CS.SE orada konuyla ilgili olabileceğini ilan ediyor.

Ooh, teşekkür ederim! Gelecekteki dil tasarım sorularımı buraya göndereceğim. :) Ve, evet, ne yazık ki 'yanlış-negatif' sorumu ve aradığımı tanımlamanın en doğru yolu değil .. Daha fazla kelime yazmam gerekiyor, böylece insanlar ne olduğumu tahmin etmiyorlar söylemeye çalışmak.
Anonsage

2
"Dilin içindeki tutarlılık" aynı zamanda jenerik
Brendan

2

Java, operatör aşırı yüklemesini desteklememektedir, bu ==yalnızca ilkel türler veya referanslar için geçerlidir anlamına gelir . Başka bir şey bir yöntemin çağrılmasını gerektirir. Tasarımcıların bunu neden yaptıkları sadece cevaplayabilecekleri bir soru. Tahmin etmek zorunda olsaydım, büyük olasılıkla operatör aşırı yüklemesinin eklemek istemedikleri karmaşıklığı getirmesi nedeniyledir.

Ben C # konusunda uzman değilim, ancak bu dilin tasarımcıları onu her ilkel structve her structbiri bir nesne olacak şekilde ayarladılar . C # operatörün aşırı yüklenmesine izin verdiğinden, bu düzenleme sadece herhangi bir sınıf için herhangi Stringbir operatörle "beklenen" şekilde çalışmasını kolaylaştırmaz. C ++ aynı şeyi sağlar.


1
"Java, operatörün aşırı yüklenmesini desteklemiyor, bunun anlamı == yalnızca ilkel türler veya referanslar için geçerlidir. Başka bir şey bir yöntemin çağrılmasını gerektirir.": Bir ==dize eşitliği anlamına gelirse , referans eşitliği için başka bir notasyona ihtiyaç duyacağımızı söyleyebiliriz.
Giorgio

@ Giorgio: Kesinlikle. Gilad Naaman'ın cevabı hakkındaki yorumuma bakın.
Blrfl

Bununla birlikte, iki nesnenin (veya bir işlecin) referanslarını karşılaştıran statik bir yöntemle çözülebilir. C # gibi, örneğin.
Gilad Naaman

@GiladNaaman: Bu sıfır toplamlı bir oyun olacak çünkü Java'nın şu anda tam tersi bir soruna neden oluyor: eşitlik bir operatörde olacak ve referansları karşılaştırmak için bir yöntem çağırmanız gerekecek. Ayrıca, tüm sınıfların bağlı olabilecek bir şey uygulama zorunluluğu getirmelisiniz ==. Bu, Java'nın uygulanma şeklini çok fazla etkileyebilecek olan operatör aşırı yüklemesini etkili bir şekilde ekliyor.
Blrfl

1
@ Blrfl: Pek değil. Reference ( ClassName.ReferenceEquals(a,b)) ' yi karşılaştırmak için her zaman tanımlanmış bir yol ==ve Equalsher ikisine de işaret eden varsayılan bir işleç ve yöntem olacaktır ReferenceEquals.
Gilad Naaman

2

Bu, diğer dillerde farklı yapılmıştır.

Object Pascal (Delphi / Free Pascal) ve C # 'da, eşitlik operatörü, dizelerde çalışırken referansları değil değerleri karşılaştırmak için tanımlanır.

Özellikle Pascal'da dize ilkel bir türdür (Pascal'ı gerçekten sevdiğim şeylerden biri, yalnızca başlatılmamış bir dize nedeniyle NullreferenceException'ı alır) (çoğu zaman) dize işlemlerini çok fazla yapan çok ucuz (başka bir deyişle, yalnızca çok megabayt dizeleri birleştirmeye başladığınızda farkedilir).

Demek Java için bir dil tasarım kararı. Dili tasarladıklarında C ++ yolunu izlerler (Std :: String gibi), böylece dizeler nesnelerdir; bu, dizeleri ilkel (yerine) yapmak yerine IMHO'yu gerçek bir dize türünden yoksun C'yi telafi etmek için bir hack yapar.

Bu yüzden, bir nedenden ötürü, sadece kendi taraflarına kolaylık sağlamak için yaptıklarını ve operatöre kodlama yapmamalarını, derleyicilere dizgiler için bir istisna yapmalarını söyleyebilirim.


Bu soruyu soruyu nasıl cevaplıyor?
gnat

Son cümleyi görün (bir düzenlemedeki uygun bir paragrafta ayırdığım).
Fabricio Araujo

1
IMHO, StringJava’da ilkel bir tür olmalıydı. Diğer türlerin aksine, derleyicinin bilmesi gereken String; ayrıca, bunun üzerindeki operasyonlar, birçok uygulama tipi için bir performans darboğazı oluşturabilecekleri (yerel destekle hafifletilebilecek) yeterince yaygın olacaktır. Tipik bir string[küçük harf], içeriğini tutmak için öbek üzerinde tahsis edilmiş bir nesneye sahip olacaktır, ancak bu nesneye hiçbir "normal" referans yoktur; bu nedenle, tek bir dolaylı olabilir Char[]veya başka bir nesneden dolaylı Byte[]olmak zorunda olmak yerine Char[].
supercat

1

Java'da, hiçbir operatörde aşırı yüklenme yoktur ve bu nedenle karşılaştırma operatörleri yalnızca ilkel türler için aşırı yüklenir.

'String' sınıfı ilkel değildir, bu nedenle '==' için aşırı yüklenme yoktur ve bilgisayarın belleğindeki nesnenin adresini karşılaştırmak için varsayılanı kullanır.

Emin değilim, ama Java 7 veya 8'de Oracle'ın derleyicide olduğu str1 == str2gibi bir istisna yaptığını düşünüyorum.str1.equals(str2)


"Emin değilim, ama Java 7 veya 8'de oracle'nın derleyicide str1 == str2'yi str1.equals (str2) olarak tanımak için bir istisna yaptığını düşünüyorum": Şaşırmam: Oracle daha az endişeli görünüyor Sun'dan daha az minimalizmle.
Giorgio

2
Doğruysa, bu çok çirkin bir hack çünkü dilin, dilin diğerlerinden farklı davrandığı bir sınıf olduğu ve referansları karşılaştıran kodu ihlal ettiği anlamına geliyor. : - @
Blrfl

1
@WillihamTotland: Tersini düşünün. İki dizeleri oluşturmak, eğer Halen s1ve s2ve onlara aynı içerikleri vermek, bunlar eşitlik (geçmesine s1.equals(s2)) karşılaştırma fakat aynı referans ( ==iki farklı nesneleri çünkü) karşılaştırması. ==Eşitlik anlamının anlamını değiştirmek, s1 == s2değerlendirmede truekullanıldığı yeri değerlendirmeye neden olur false.
Blrfl

2
@Brlfl: Bu doğru olsa da, dizeler değişmez, internable nesneler olduğu için, ilk olarak dayanması son derece kötü bir şey gibi geliyor.
Williham Totland,

2
@Giorgio: "Java 7 veya 8 oracle, derleyicide str1 == str2'yi str1.equals (str2) olarak tanımak için bir istisna yaptı" Hayır, Java Dil Belirtimi diyor: Referans Eşitliği İşleçleri : "Eşitlik işlecinin işlenenleri ya referans tipinin ya da null tipinin her ikisi de, işlem nesne eşitliğidir. " Hepsi bu kadar millet. Java 8'in ilk taslağında da bununla ilgili yeni bir şey bulamadım .
David Tonhofer,

0

Java, ==bir işlenenin diğerinin türüne dönüştürülebildiği durumlarda operatörün yasal olması gerektiği ve bu tür bir dönüşümün sonucunu dönüştürülmemiş işlenen ile karşılaştırması gerektiği konusunda temel bir kuralı yerine getirmek için tasarlanmış gibi görünmektedir .

Bu kural, Java'ya özgü değildir, ancak dilin türüyle ilgili diğer yönlerinin tasarımı üzerinde geniş kapsamlı (ve IMHO talihsiz) etkileri vardır. Davranışlarını belirtmek için temiz olurdu ==tipleri X ve Y kombinasyonları işlenen tiplerinin belirli kombinasyonları ile ilgili olarak, ve korusun x1==y1ve x2==y1anlamına gelmeyeceğine x1==x2, ama dil nadiren bu felsefesi altında, [bunu double1 == long1belirtmek gerekir ya tam bir temsili double1değil , derlemeyi reddetme;long1int1==Integer1yasaklanmalı, ancak bir nesnenin belirli bir değere sahip kutulu bir tamsayı olup olmadığını test etmenin uygun ve etkili bir atma aracı olmamalıdır (kutulu bir tamsayı olmayan bir şeyle kıyaslandığında basitçe geri dönmelidir false)].

Uygulayarak ilişkin olarak ==dizeleri operatörün, Java türüne işlenenler arasında doğrudan karşılaştırmalar yasak olsaydı Stringve Objectdavranışlarındaki, oldukça iyi kaçınılması olabilirdi sürprizler ==ama şaşırtıcı olmaz böyle karşılaştırmalar için uygulamak hiçbir davranış yoktur. Yazılı olarak tutulan iki dize referansı Object, yazılan tutulan referanslardan farklı davranmak String, bu davranışlardan herhangi birinin yasal bir karışık tür karşılaştırmasından farklı olmasından çok daha az şaşırtıcı olurdu. Eğer String1==Object1yasal ise, bu davranış String1==String2ve Object1==Object2eşleşmenin tek yolunun String1==Object1birbiriyle eşleşmesi olacağı anlamına gelir .


Bir şeyi kaçırmalıyım, ancak ==nesnelerdeki IMHO basitçe (null-safe) eşittir ve kimlik karşılaştırması için başka bir şey (örneğin, ===veya System.identityEqual) kullanılmalıdır. İlkellerin ve nesnelerin karıştırılması başlangıçta yasaklanacaktı (1.5'ten önce bir otomatik kutulama yoktu) ve sonra bazı basit kurallar bulunabildi (örn. Boş güvenli unbox, sonra kullan, sonra karşılaştır).
maaartinus 17:14

@maaartinus: İyi bir dil tasarımının değer ve referans eşitliği için ayrı eşitlik operatörleri kullanması gerekir. Ben kavramsal bir olması mümkün olurdu kabul ederken int==Integeroperatör dönüşü falseeğer Integerdeğerleri karşılaştırmak null, aksi takdirde, bu yaklaşım davranışı aksine olurdu ==koşulsuz öncekiyle aynı türe hem işlenen coerces diğer tüm durumlarda, onları karşılaştırarak. Şahsen acaba otomatik int==Integerolmayan
kutucuğun

... çünkü otomatik kutulama intve referans karşılaştırma yapmak aptalca olurdu [ama her zaman başarısız olmaz]. Aksi takdirde, NPE ile başarısız olabilecek örtük bir dönüştürmeye izin vermek için hiçbir neden göremiyorum.
supercat,

Benim fikrim tutarlı olduğunu düşünüyorum. Sadece daha iyi dünyada, ==bununla ilgisi olmadığını unutmayın identityEquals. +++ "değer ve referans eşitliği için ayrı eşitlik operatörleri" - hangileri? Ben ilkel hem dikkate alacağını ==ve equalsyapıyor olarak değer anlamında karşılaştırma equalsbakar değerin referans. +++ Ne zaman ==kastedilirse equals, o zaman int==Integerotomatik kutulamayı yapmalı ve null-safe eşitlerini kullanarak referansları karşılaştırmalısınız. +++ Korkarım benim fikrim gerçekten benim değil, sadece Kotlin'in yaptığı.
maaartinus

@maaartinus: ==Referans eşitliği hiç test edilmediyse, makul bir şekilde boş değer-değer eşitliği testi yapabilirdi. O aslında yaptığı deney referans eşitliği, ancak tutarsızlık olmadan karışık referans / değer karşılaştırmaları işleyebilir nasıl ciddi sınırlar. Ayrıca, Java'nın, işleçlerin, söz konusu türlerin birleşimine dayanan özel davranışlar vermek yerine, her iki işleyiciyi de aynı türe yükseltdiği fikrine dayandığını unutmayın. Örneğin, 16777217==16777216.0fgeri döner trueçünkü ilk işlenenin float
kayıtsız

0

Genel olarak, iki nesne referansının aynı nesneyi gösterip göstermediğini test edebilmek için çok iyi bir neden vardır. Yazdığım birçok kez yaşadım

Address oldAddress;
Address newAddress;
... populate values ...
if (oldAddress==newAddress)
... etc ...

Bu gibi durumlarda eşit bir fonksiyona sahip olabilir veya olmayabilir. Bunu yaparsam, eşittir işlevi her iki nesnenin tüm içeriğini karşılaştırabilir. Genellikle sadece bazı tanımlayıcıları karşılaştırır. "A ve B, aynı nesneye referanslar" ve "A ve B, aynı içeriğe sahip iki farklı nesnedir", elbette, iki farklı fikir.

Dizeler gibi, değiştirilemeyen nesneler için bunun daha az sorun olduğu muhtemelen doğrudur. Değişmez nesnelerle, nesneyi ve değeri aynı şey olarak düşünmeye meyilliyiz. En azından "biz" derken, "ben" demek istiyorum.

Integer three=new Integer(3);
Integer triangle=new Integer(3);
if (three==triangle) ...

Elbette yanlış döndürür, ancak doğru olması gerektiğini düşünen birini görebilirim.

Ancak, == genel olarak Nesnelerin içeriğini değil, başvuru tutamaçlarını karşılaştırdığınızı söylediğinizde, Dizeler için özel bir durum oluşturmak potansiyel olarak kafa karıştırıcı olabilir. Buradaki başka birinin dediği gibi, ya iki String nesnesinin tutamaçlarını karşılaştırmak istersen? Bunu sadece Strings için yapacak özel bir fonksiyon olur mu?

Ve ne hakkında ...

Object x=new String("foo");
Object y=new String("foo");
if (x==y) ...

Bu yanlış mı, çünkü iki farklı nesne mi, yoksa içeriği eşit olan bir dize oldukları için mi doğru?

Yani evet, programcıların bununla nasıl karıştığını anlıyorum. Ben kendim yaptım, eğer demek istemiyorum, eğer myString == "foo", eğer myString.equals ("foo") ise. Ancak == işlecinin anlamını tüm nesneler için yeniden tasarlamanın dışında, bunun nasıl ele alınacağını bilmiyorum.


JVM'deki Scala gibi diğer modern dillerin =="eşit dizge" anlamına geldiğini unutmayın.
Andres F.

@AndresF. (shrug) Java’da "<" "daha az" anlamına gelirken, XML’de "etiket" açar. VB'de "=", "ye eşittir" anlamına gelirken, Java'da yalnızca atama için kullanılır. Vb Farklı dillerin aynı şeyleri ifade etmek için farklı semboller veya farklı şeyleri ifade etmek için aynı semboller kullanması şaşırtıcı değildir.
Jay

Cevabında kazmak değildi. Bu sadece bir yorumdu. Sadece Java'dan daha modern bir dilin ==, en sonunda bahsettiğiniz gibi , anlamını yeniden tasarlama şansını bulduğuna işaret ediyordum .
Andres F.

@AndresF. Ve cevabım, yorumunuzda kazı değildi, sadece farklı dillerin bu konulara farklı şekillerde yaklaştığını söylemek. :-) Aslında VB'nin bu yöntemi kullanma şeklini seviyorum ... VB bilgisayarlarından gelen tıslamalar ve yükselmeler için duraklama ... "=" ilkel olsun veya olmasın, her zaman değeri (sistem tanımlı türler için) karşılaştırır. "Is" iki nesnenin tutamaçlarını karşılaştırır. Bu bana daha sezgisel geliyor.
Jay

Elbette. Ancak Scala, Java'ya Visual Basic'ten çok daha yakın. Scala'nın tasarımcılarının Java'nın kullanımının ==hataya açık olduğunu fark ettiklerini düşünüyorum .
Andres F.

0

Bu geçerli bir sorudur Stringsve sadece dizeleri için değil, aynı zamanda örneğin bazı "değer" temsil eden diğer değişmez Nesneler için Double, BigIntegerve hatta InetAddress.

==Operatörü Strings ve diğer değer sınıfları ile kullanılabilir hale getirmek için üç alternatif görüyorum:

  • Derleyiciye tüm bu değer sınıflarını ve içeriklerini karşılaştırmanın yolunu bildirin. java.langPaketten sadece bir avuç sınıf olsaydı, bunu düşünürdüm, ama bu InetAddress gibi durumları kapsamıyor.

  • Operatör aşırı yüklemesine izin verin, böylece bir sınıf ==karşılaştırma davranışını tanımlar .

  • Ortak yapıcıları kaldırın ve bir havuzdan örnekleri döndüren, her zaman aynı değeri aynı örneği döndüren statik yöntemleri kullanın. Bellek sızıntılarını önlemek için, havuzda Java 1.0'da bulunmayan SoftReferences gibi bir şeye ihtiyacınız var. Ve şimdi, uyumluluğu korumak için, String()inşaatçılar artık kaldırılamaz.

Bugün yapılabilecek tek şey operatörün aşırı yüklenmesini sağlamak olacak ve şahsen Java'nın bu yola gitmesini istemem.

Bana göre, kod okunabilirliği çok önemlidir ve bir Java programcısı, operatörlerin dil belirtiminde tanımlanan sabit bir anlama sahip olduğunu bilir, oysa yöntemler bazı kodlarla tanımlanır ve anlamları yöntemin Javadoc'unda aranmalıdır. String karşılaştırmalarının ==operatörü kullanamayacağı anlamına gelse bile bu ayrımdan ayrılmak istiyorum .

Java'nın beni rahatsız eden karşılaştırmalarının sadece bir yönü var: otomatik boks ve unboxing'in etkisi. İlkel ve sarıcı türü arasındaki ayrımı gizler. Ama onları karşılaştırdığınızda ==, onlar çok farklı.

    int i=123456;
    Integer j=123456;
    Integer k=123456;
    System.out.println(i==j);  // true or false? Do you know without reading the specs?
    System.out.println(j==k);  // true or false? Do you know without reading the specs?
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.