Bir örnek, daha belirli bir türden başka bir örneğe eşit olabilir mi?


25

Bu makaleyi okudum: Java'da Eşitlik Yöntemi Nasıl Yazılır .

Temel olarak, kalıtımı destekleyen bir equals () yöntemi için bir çözüm sunar:

Point2D twoD   = new Point2D(10, 20);
Point3D threeD = new Point3D(10, 20, 50);
twoD.equals(threeD); // true
threeD.equals(twoD); // true

Ama bu iyi bir fikir mi? bu iki durum eşit görünmektedir ancak iki farklı karma koduna sahip olabilir. Bu biraz yanlış değil mi?

Bunun yerine operandları yayınlayarak daha iyi olacağına inanıyorum.


1
Bağlantıda verilen renkli noktalara sahip olan örnek benim için daha anlamlı. Bir 2B noktanın (x, y) sıfır Z bileşenine (x, y, 0) sahip bir 3B nokta olarak görülebileceğini düşünürdüm ve eşitliğinizin durumunda yanlış dönmesini istiyorum. Aslında, makalede, bir ColoredPoint'in açıkça bir Noktadan farklı olduğu ve her zaman yanlış döndürdüğü söylenir.
coredump

10
Ortak sözleşmeleri ihlal eden derslerden daha kötü bir şey yok ... Bu tür alışkanlıkları programcılardan çıkarmak yıllar alıyor.
corsiKa

3
@coredump Bir 2B noktanın sıfır zkoordinat olarak kabul edilmesi, bazı uygulamalar için yararlı bir kural olabilir (eski verileri işleyen eski CAD sistemleri akla gelir). Ancak bu keyfi bir kongredir. 3 veya daha fazla boyutlu uzaylardaki düzlemlerin keyfi yönelimleri olabilir ... ilginç sorunları ilginç yapan da budur.
ben rudgers 29:15

Yanıtlar:


71

Bu eşitlik olmamalıdır çünkü geçişliliği bozar . Bu iki ifadeyi göz önünde bulundurun:

new Point3D(10, 20, 50).equals(new Point2D(10, 20)) // true
new Point2D(10, 20).equals(new Point3D(10, 20, 60)) // true

Eşitlik geçişli olduğundan, bu, aşağıdaki ifadenin de doğru olduğu anlamına gelmelidir:

new Point3D(10, 20, 50).equals(new Point3D(10, 20, 60))

Ama elbette - öyle değil.

Bu nedenle, döküm fikriniz doğrudur - Java’da döküm yapmak, sadece referansın türünün kullanılması anlamına gelir. Burada gerçekten istediğiniz şey Point2D, bir Point3Dnesneden yeni bir nesne yaratacak bir dönüştürme yöntemidir . Bu aynı zamanda ifadeyi daha anlamlı kılacaktır:

twoD.equals(threeD.projectXY())

1
Bu makalede, geçişliliği bozan ve çeşitli çalışma ortamları sunan uygulamalar anlatılmaktadır. 2B noktalara izin verdiğimiz bir alanda, üçüncü boyutun önemli olmadığına zaten karar verdik. ve böylece (10, 20, 50)eşittir (10, 20, 60)iyidir. Sadece 10ve umurumuzda 20.
ben rudgers 28:15

1
Kendisini temsil etmek için Point2Dbir projectXYZ()yöntem olmalı mı Point3D? Başka bir deyişle, uygulamalar birbirini tanıyor mu?
hjk

4
@hjk Kurtulmak Point2Ddaha basit görünüyor çünkü 2B noktaların yansıtılması, düzlemlerinin önce 3B alanda tanımlanmasını gerektirir. 2B nokta düzlem olduğunu biliyorsa, o zaman zaten bir 3B nokta. Olmazsa, yansıtamaz. Abbott's Flatland'ı hatırlatıyorum .
ben rudgers

@ benrudgers Yine de, Plane3Düç boyutlu uzayda bir düzlem tanımlayacak bir nesneyi tanımlayabilirsiniz, o düzlemin "üçüncü eksen" için liftbir Point2Dve bir sayı kabul edecek bir metodu (2D-> 3D kaldırılıyor, yansıtmıyor) olabilir. "- normal düzlem boyunca düzlemden uzaklık. Kullanım kolaylığı için, ortak düzlemleri statik sabitler olarak tanımlayabilirsiniz, böylece şöyle bir şey yapabilirsinizPlane3D.XY.lift(new Point2D(10, 20), 50).equals(new Point3D(10, 20, 50))
Idan Arye

@IdanArye 2B noktaların izdüşüm yöntemine sahip olması önerisi üzerine yorum yapıyordum. Kaldırma yöntemlerine sahip uçaklara gelince, anlam ifade etmek için iki argüman gerektireceğini düşünüyorum: 2B nokta ve üzerinde durduğu düşünülen düzlem, yani eğer noktaya sahip değilse, gerçekten bir projeksiyon olması gerekir ... ve eğer bu konuya sahipse, neden sadece bir 3B noktaya sahip değil, sorunlu bir veri türü ve kludged bir metodun kokusunu almıyorsunuz? YMMV.
ben rudgers

10

Alan J. Perlis'in bilgeliğini düşünerek makaleyi okumaktan uzaklaşıyorum :

Epigram 9. Bir veri yapısında 100 işlevin çalışması, 10 veri yapısında 10 işlevin kullanılması daha iyidir.

“Eşitlik” hakkını elde etmenin , Martin Ordersky'yi Scala'nın mucidi geceleri ayakta tutan bir tür problem olması, equalsmiras ağacında geçersiz kılmanın iyi bir fikir olup olmadığı konusunda duraklatmalıdır .

Kazanmak için şanssız olduğumuzda olan şey ColoredPoint, geometrimizin başarısız olması, çünkü iyi olanı yapmak yerine veri türlerini çoğaltmak için miras kullandık. Bu, geri dönüp kalıtım ağacının kök düğümünü equalsiş yapmak için değiştirmek zorunda kalmasına rağmen . Neden sadece bir ekleme zve colorhiç Point?

Bunun iyi nedeni, bunu yapar Pointve ColoredPointfarklı alanlarda çalışır ... en azından bu alanlar hiç karışmazsa. Ancak durum buysa, geçersiz kılmamız gerekmez equals. Karşılaştırma ColoredPointve Pointeşitlik için, sadece karışmasına izin verilen üçüncü bir alanda anlamlıdır. Ve bu durumda, eşitlik semantiklerini birinden veya diğerinden veya unmingled alan adlarından her ikisinden de eşitlik semantiği uygulamaya çalışmak yerine, bu üçüncü alana göre uyarlanmış "eşitlik" muhtemelen daha iyidir. Başka bir deyişle, “eşitlik”, her iki taraftan da çamur aktığımız yere göre yerel olarak tanımlanmalıdır, çünkü düşüncenin yazarı, altı ay önce saat 2'de iyi bir fikir olduğu düşünüldüğünde bile ColoredPoint.equals(pt), başarısız olmak istemeyebiliriz . .PointColoredPoint


6

Eski programlama tanrıları, sınıfları ile nesne yönelimli programlama icat ederken, bir nesne için iki ilişkinin oluşması ve mirasa geldiğine karar verdiler: "bir" ve "vardır".
Bu, alt sınıfların ebeveyn sınıflarından farklı olma problemini kısmen çözdü, ancak kodları kırmadan kullanılabilir hale getirdi. Bir alt sınıf örneği "bir" süper sınıf nesnesi olduğundan ve doğrudan bunun yerine kullanılabildiğinden, alt sınıfın daha fazla üye işlevi veya veri üyesi olmasına rağmen, "bir" değeri, üst öğenin tüm işlevlerini yerine getireceğini ve tüm işlevlerini yerine getireceğini garanti eder. üyeler. Böylece bir Point3D'nin "Point" ve "Point2D" nin "Point" olduğunu ve ikisinin de Point'ten miras aldığını söyleyebilirsiniz. Ek olarak, bir Point3D, Point2D'nin bir alt sınıfı olabilir.

Bununla birlikte, sınıflar arasındaki eşitlik, alana özgüdür ve yukarıdaki örnek programcının programın doğru çalışması için neye ihtiyaç duyduğu konusunda belirsizdir. Genel olarak, matematik alanı kuralları takip edilir ve karşılaştırmanın kapsamını sadece bu durumda iki boyutla sınırlarsanız, ancak tüm veri üyelerini karşılaştırmazsanız, verilerin eşitliği sağlanır.

Böylece eşitliği daraltan bir tablo elde edersiniz:

Both objects have same values, limited to subset of shared members

Child classes can be equal to parent classes if parent and childs
data members are the same.

Both objects entire data members are the same.

Objects must have all same values and be similar classes. 

Objects must have all same values and be the same class type. 

Equality is determined by specific logical conditions in the domain.

Only Objects that both point to same instance are equal. 

Genelde problem alanınızda gerekli tüm fonksiyonları yerine getirebilecek en katı kuralları seçersiniz. Sayılar için yerleşik eşitlik testleri, matematik amaçları için olabildiğince kısıtlayıcı olacak şekilde tasarlanmıştır, ancak programcının yuvarlama / aşağılama, kesme, gt, lt, vb. . Zaman damgalarına sahip nesneler genellikle oluşturma zamanlarına göre karşılaştırılır ve bu nedenle her bir örnek benzersiz olmalıdır, böylece karşılaştırmalar çok özel olur.

Bu durumda tasarım faktörü nesneleri karşılaştırmak için etkili yollar belirlemektir. Bazen tüm nesnelerin veri üyelerini yinelemeli bir karşılaştırması yapmanız gereken şeydir ve çok fazla veri üyesi olan çok ve çok sayıda nesneniz varsa bu çok pahalı olabilir. Alternatifler yalnızca ilgili veri değerlerini karşılaştırmak veya nesnenin diğer benzer nesnelerle hızlı bir karşılaştırma yapmak için ilgilendiği veri üyelerinin bir karma değerini üretmesini sağlamak, karşılaştırmaları daha hızlı ve daha az işlemci yoğunlaştırmak ve belki de bu nesnelerin karşılaştırılmasını sağlamak için koleksiyonları sıralı ve budanmış tutmaktır. toplanacak verilerle aynıdır ve tek bir nesneye kopyalayan bir işaretçi yerine konur.


2

Kural, ne zaman geçersiz kıldığınızda hashcode(), geçersiz kılarsınız equals()ve bunun tersi de geçerlidir. Bunun iyi bir fikir olup olmadığı, kullanım amacına bağlıdır. Şahsen, isLike()aynı etkiyi elde etmek için farklı bir yöntemle ( veya benzeri) gidecektim .


1
Eşittir geçersiz kılmadan hashCode komutunu geçersiz kılmak doğru olabilir. Örneğin, bir kişi aynı eşitlik şartı için farklı bir karma algoritma test etmek için bunu yapar.
Patricia Shanahan,

1

Kamuya açık olmayan sınıfların, aynı türdeki bilgileri temsil ettikleri takdirde, farklı türdeki nesnelerin birbirlerini "eşit" olarak değerlendirmelerini sağlayan, ancak Java'nın, her sınıfın hangi sınıfları taklit edebileceği anlamına gelmediğinden, eşitlik test yöntemine sahip olmaları genellikle yararlıdır. diğerinde, farklı temsillere sahip eşdeğer nesnelerin bulunmasının mümkün olduğu durumlarda, halka açık tek bir ambalaj türüne sahip olmak genellikle iyidir.

Örneğin, değişmez bir 2D değer matrisini içeren bir sınıfı düşünün double. Dışarıdaki bir yöntem 1000 boyutunda bir kimlik matrisi isterse, ikincisi bir çapraz matris ister ve 1000 tane içeren bir diziyi geçer ve üçüncüsü bir 2D matris ister ve 1000x1000 dizisini geçer ve buradaki birincil köşegen üzerindeki öğelerin tümü 1.0 ve diğerleri sıfırdır, üç sınıfa verilen nesneler dahili olarak farklı ilki depolarını kullanabilir (ilki boyut için tek bir alana sahip, ikincisi bin element dizisine sahip, üçüncüsü bin 1000 element dizisine sahip) birbirlerini eşdeğer olarak bildirmeliler (çünkü üçü de 1000x1000 değişmez matrisini diyagonal üzerinde olanlarla ve başka her yerde sıfırlarla kapsüllenmiş halde).

Farklı destek mağaza tiplerinin varlığını gizlemesinin ötesinde, sarıcı, eşdeğerlik için öğeleri kontrol etmek genellikle çok aşamalı bir işlem olacağından karşılaştırmaları kolaylaştırmak için de faydalı olacaktır. İlk maddeye, ikinciye eşit olup olmadığını bilip bilmediğini sorun; Eğer bilmiyorsa, ikinciye, birincisine eşit olup olmadığını bilip bilmediğini sorun. Her iki nesne de bilmiyorsa, her bir diziye kendi bireysel öğelerinin içeriği hakkında bilgi isteyin (biri uzun-yavaş bireysel ürün karşılaştırma rotasını yapmaya karar vermeden önce başka kontroller ekleyebilir].

Bu senaryoda her nesne için denklik testi yönteminin üç durumlu bir değer ("Evet eşdeğerim", "Hayır eşdeğer değilim" veya "Bilmiyorum") döndürmesi gerekeceğini unutmayın. bu nedenle normal "eşittir" yöntemi uygun olmaz. Herhangi bir nesne, başkaları hakkında sorulduğunda basitçe "bilmiyorum" cevabını verebilirken, örneğin, herhangi bir kimlik matrisi veya diyagonal matrisi sormaktan rahatsız etmeyecek bir diyagonal matrise mantık eklenmesi, bu tür karşılaştırmalar arasındaki karşılaştırmaları büyük ölçüde hızlandırır. türleri.

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.