Neden .compareTo () bir arayüzde .equals () Java sınıfındayken?


30

Nedenini bilmek istiyorum .compareTo()içindedir Comparablegibi bir yöntem ise arayüzünde .equalsbulunan Objectsınıfın. Bana göre, böyle bir yöntemin neden zaten sınıfta .compareTo()olmadığı keyfi görünüyor Object.

Kullanmak .compareTo()için Comparablearayüzü uygular ve .compareTo()yöntemi kendi amaçlarınız için uygularsınız . İçin .equals()bütün sınıflar devralan beri yöntemle, sadece, sınıfında yöntemini geçersiz Objectsınıfında.

Sorum şu: neden böyle .compareTo()bir sınıftan ziyade uyguladığınız bir arayüze benzer bir yöntem Object? Aynı şekilde, neden .equals()sınıfta Objectdeğil de bir arayüzde uygulanacak yöntem var ?



2
Java dilinin tasarım seçimidir (mutlaka doğru seçim olduğu anlamına gelmez). Diğer dillerde, örneğin Haskell , değer eşitliği elde etmek için eşitlik arayüzünü uygulamanız gerekir (aslında Eqtip sınıfına bir örnek sağlarsınız).
mucaho

Yanıtlar:


58

Bütün nesneler karşılaştırılamaz, ancak bütün nesneler eşitlik açısından kontrol edilebilir. Başka bir şey yoksa, biri bellekte aynı yerde iki nesnenin var olup olmadığını görebilir (referans eşitliği).

compareTo()İki Threadnesnede bunun anlamı nedir ? Bir iş parçacığı diğerinden "daha büyük" nasıl? İki ArrayList<T>s nasıl karşılaştırılır ?

ObjectSözleşme için geçerli tüm Java sınıfları. Bir sınıf bile kendi sınıfının diğer örnekleri ile karşılaştırılamazsa Object, arayüzün bir parçası olmasını gerektiremez.

Joshua Bloch, bir sınıfın neden uygulamak istediğini açıklarken "doğal düzen" anahtar sözcüklerini kullanıyor Comparable. Yukarıdaki örneklerde bahsettiğim gibi, her sınıfın doğal bir düzeni yoktur, bu nedenle her sınıfın uygulamaması Comparableveya yönteme Objectsahip olmaması gerekir compareTo.

... compareToyöntem, içinde bildirilmedi Object. ... O kadar karakterinde benzer Objectbireyin equalsbasit eşitlik karşılaştırmalar ek olarak sipariş karşılaştırmaları izin haricinde, yöntemin ve geneldir. ComparableBir sınıf uygulayarak , örneklerinin doğal bir sıraya sahip olduğunu belirtir .

Etkili Java, İkinci Baskı : Joshua Bloch. Madde 12, Sayfa 62. Elips, diğer bölümlere ve kod örneklerine referansları kaldırır.

Eğer durumlarda do olmayan bir bir sipariş empoze etmek istiyorum Comparabledoğal bir sipariş yok sınıfın, her zaman bir sağlayabilmektedir Comparatorbu bir çeşit yardıma örneği.


3
Eğer soyut bir sınıf değildir ve bu nedenle aNullPointerException.compareTo (anUnsupportedFlavorException anlam hayata olurdu hariç olmak üzere compareTo (yaklaşık düşünme başladığınızda daha eğlenceli olurdu) vardır ... anlam?

10
tüm nesneler eşitlik açısından kontrol edilebilir Java'da evet, fakat genel olarak hayır. Eşitlik karşılaştırmasının bir anlam ifade etmediği bazı nesneler vardır (referans eşitliği bile değil) - örneğin, tekiller. ValueEquality ve ReferenceEquality gibi arayüzler (soyut sınıflar) olabilir. Bu kadar kötü bir fikir bile olmayabilir ...
qbd

5
"tüm nesneler eşitlik için kontrol edilebilir. Başka bir şey olmazsa, bellekte aynı yerde iki nesne olup olmadığı görülebilir (referans eşitliği)." - ==ikincisine sahip olduğumuz için, bunun içi boş bir halka var. Gereksiz varsayılan dikkate almayan bir geçerli nedenleri bulabilirsiniz değil varsaymak equalsdeğil her türlü bir denklik ilişkisi destekleyebilir beri tüm sınıfları üzerinde.
Raphael,

3
Eşitliği tanımlamanın mantıklı olmadığı iki tür örnek: akışlar (örn. Tembel potansiyel sınırsız listeler veya sonsuz hassas sayılar) ve fonksiyonlar. İlki, eşitliği sağlamanın sınırsız bir şekilde karşılaştırmayı gerektirebileceği sorununa sahiptir. İki fonksiyonun eşit olup olmadığına karar vermek kararsızdır. Bu tip iki örneğin aynı bellek konumunda olup olmadığını sormak 1) çok kullanışlı değil ve 2) müşterilerin uygulama detaylarının ne olması gerektiğine duyarlı kod yazmasına izin veriyor. Bugün size her sorduğunuzda size aynı sınırsız listenin yeni bir örneğini verebilirim, yarın not alabilirim.
Doval

6
@Snowman Uygulama detaylarını ortaya koymasıyla bir işe yaramaz olması, izin vermemek için yeterli bir nedendir. Java 8'deki her "değere dayalı" sınıfın hemen hemen hepsinde "Kullanırsanız ne olacağından sorumlu değiliz" diyen bir kazan vardır ==; çünkü bu sınıfların nasıl somutlaştırıldığı bir uygulama detayıdır, ancak dil gizlenmeyi imkansız kılar. İki Integerkişiyi referans ile karşılaştıran herkesin bir aptal olduğunu söyleyebiliriz , ancak karşılaştırmanın başlamasını sağlamak hala aptalca.
Doval

8

§4.3.2 JLS tanımlar classşu şekilde nesne:

4.3.2. Sınıf Nesnesi

Sınıf Object, diğer tüm sınıfların bir üst sınıfıdır (§8.1.4).

Tüm sınıf ve dizi türleri Object, aşağıdaki gibi özetlenen sınıf yöntemlerini miras alır (§8.4.8) :

  • Bu yöntem clone, bir nesnenin kopyasını yapmak için kullanılır.

  • Yöntem equals, referans değil karşılaştırmaya dayalı değere dayanan nesne eşitliği kavramını tanımlar.

  • Yöntem finalize, bir nesne yok edilmeden hemen önce çalıştırılır (§12.6).

  • Yöntem getClass, nesnenin sınıfını temsil eden Class nesnesini döndürür.

  • ClassHer referans türü için bir nesne vardır. Örneğin, bir sınıfın tam adını, üyelerini, hemen üst sınıfını ve uyguladığı tüm arabirimleri keşfetmek için kullanılabilir.

    İçin bir yöntem çağırma ifade türü getClassolup Class<? extends |T|>burada Tsınıf veya arayüz için (§15.12.1) arama getClass.

    Bildirilen bir sınıf yöntemi synchronized(§8.4.3.6), sınıfın Class nesnesiyle ilişkili monitörde senkronize olur.

  • Yöntem hashCode, eşittir ile birlikte, gibi bir tabloda çok yararlıdır java.util.Hashmap.

  • Yöntemler wait, notifyve notifyAlleşzamanlı programlama kullanarak parçacığı (§17.2) kullanılmaktadır.

  • Yöntem toString, nesnenin bir String gösterimini döndürür.

Yani, bu yüzden equalsvar Objectama compareToayrı bir arayüzde. ObjectMümkün olduğunca az tutmak istediklerini tahmin ediyorum . Muhtemelen düşündüm neredeyse tüm Objects gerekir equalsve hashCode(eşitlik testinin sadece bir form gerçekten olan) ancak tüm nesneler bir kavram olması gerekir sipariş nedir, compareToiçin kullanılır.


Sanırım teorik olarak bir arayüz olabilir, Equitable<T>ancak Objectuygulandığı takdirde her sınıf bir olur Equitable<Object>. Bu noktada, bir fark var mı? Gerçekten de değil, karmaşıklıkta evet.
Kaptan Adam

1
@CaptainMan yılında .Net, objectsahip Equals(object)sadece Java gibi, aynı zamanda orada IEquatable<T>arayüzü. Varlığının birincil nedeni T, Java'da mümkün olmayan bir değer türü olduğunda boks yapmaktan kaçınmaktır .
07:15 'de salı

hashCode bir eşitlik testi biçimi değildir , çünkü karma çarpışmalar vardır. A ve B eşit ise, aynı hashCode'lara sahiptirler, fakat A ve B aynı hashCode'a sahipse, bu eşit oldukları anlamına gelmez!
Josef

Aslında, cevabınız eski bir JLS'ye ( titanium.cs.berkeley.edu/doc/java-langspec-1.0.pdf ) geçmekten çok fayda sağlayacaktır - neden doğrudan equalsbildirildiği konusunda çok daha iyi bir alıntı yaptı Object: The methods equals and hashCode are declared for the benefit of hashtables such as java.util.Hashtable (§21.7)- Java tasarımı olarak geriye uyumludur, Java 1.0 tasarım tercihi olduğu equalsyerde olmanın asıl nedenidir .
vaxquis

önerdiğim düzenleme büyük olasılıkla "çok sert" olduğu için reddedilecektir, çünkü cevabınıza sadece Ctrl + C / Ctrl + V ile ilgili bilgileri
girmelisiniz

2

Snowman'ın mükemmel cevabına ek olarak, Comparableuzun zamandır genel bir arayüz olduğunu unutmayın . Bir tür uygulanmaz compareTo(object), kendi türünün compareTo(T)nerede olduğunu uygular T. Bu uygulanamaz object, çünkü ondan objecttüretilecek sınıfı bilmiyor.

objectbir compareTo(object)metodu tanımlayabilirdi , ancak bu sadece Snowman'ın işaret ettiği şeye değil, iki ArrayList<T>saniye arasında veya iki Threadsaniye arasında bir kıyaslamaya ArrayList<T>ve hatta bir ile bir arasında bir kıyaslamaya izin verebilirdi Thread. Bu daha da saçma.


0

İki nesne referansım olduğunu varsayalım: X String, "George" içeriğini tutmanın bir örneğini tanımlar ; Y Pointkoordinatları tutma örneğini tanımlar [12,34]. Aşağıdaki iki soruyu düşünün:

  • X ve Y, eşdeğer nesneleri tanımlar mı?

  • X, Y'den önce, sonra veya eşdeğer olarak mı sıralanmalı?

X ve Y'nin ilişkisiz türlerin örneklerini tanımlaması, ilk soru göz önüne alındığında herhangi bir sorun teşkil etmez. Nesneler, yalnızca türleri eşdeğer olduklarını tanımlayan ortak bir temeli paylaşırsa eşit kabul edilebilir; beri Stringve Pointböyle tabanını (onların tek ortak baz tipi olmayan eşdeğer olarak tüm farklı nesneler ile ilgili) cevabı basitçe "hayır" dır var.

Bununla birlikte, türlerin ilişkisiz olması, ikinci soruya ilişkin büyük bir sorun teşkil etmektedir. Bazı türleri kendi örnekleri arasında sipariş ilişkileri tanımlamak ve bazı sipariş ilişkileri bile birden fazla türde üzerinde uzatabilir [örn mümkün olacağını BigIntegerve BigDecimalher iki tip örnekleri diğer örnekleri göre sıralanır sağlayacak karşılaştırma yöntemlerini tanımlamak için], ancak Genel olarak iki keyfi örnek almak ve "X'in Y'ye önce, sonra veya eşdeğer olması gerekir mi?" diye sormak ve bir toplam sipariş türetmek mümkün değildir. Nesnelerin toplam olmasa bile tutarlı bir sipariş vermeleri istendiyse "Y'ye göre X'in önce, sonra, eşdeğer veya sırasız mı sıralanmalı" sorulması mümkün olabilirbir, ancak çoğu sıralama algoritması toplam sipariş gerektirir. Bu nedenle, compareToeğer " nesne belirtilmemiş " geçerli bir geri dönüş ise tüm nesneler bir yöntem uygulasa bile, böyle bir yöntem varlığını haklı çıkarmak için yeterli olmaz.

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.