Java nesnelerini equals () ve hashcode () ile karşılaştırma

Bu ise Java Challenger öğrenmek nasıl olacak equals()ve hashcode()Java programlarında nesne karşılaştırmalar etkin ve kolay hale getirmek için birleştirir. Basitçe söylemek gerekirse, bu yöntemler iki nesnenin aynı değerlere sahip olup olmadığını doğrulamak için birlikte çalışır.  

Olmazsa equals()ve bir nesnedeki her alanı karşılaştırarak hashcode()çok büyük " if" karşılaştırmalar yapmamız gerekirdi . Bu, kodu gerçekten kafa karıştırıcı ve okumayı zorlaştırır. Bu iki yöntem birlikte, daha esnek ve uyumlu kod oluşturmamıza yardımcı olur.

Java Challengers kaynak kodunu alın.

Java'da eşittir () ve karma kodu () geçersiz kılma

Yöntemi geçersiz kılma , Polimorfizm'den yararlanmak için ana sınıfın veya arayüzün davranışının alt sınıfa tekrar yazıldığı (geçersiz kılınan) bir tekniktir. ObjectJava'da her biri bir equals()ve bir hashcode()yöntem içerir , ancak düzgün çalışması için geçersiz kılınmaları gerekir.

İle nasıl ağır basan çalıştığını anlamak için equals()ve   hashcode()biz çekirdek Java sınıfları içinde bunların uygulanmasını çalışabilirsiniz. Sınıftaki equals()yöntem aşağıdadır Object. Yöntem, geçerli örneğin daha önce geçirilen ile aynı olup olmadığını kontrol ediyor Object.

 public boolean equals(Object obj) { return (this == obj); } 

Ne zaman hashcode()yöntem geçersiz değil, varsayılan yöntemi Objectsınıfa çağrılır. Bu yerel bir yöntemdir , yani C gibi başka bir dilde çalıştırılacak ve nesnenin bellek adresiyle ilgili bazı kodlar döndürecektir. (JDK kodu yazmıyorsanız, bu yöntemin tam olarak nasıl çalıştığını bilmek o kadar önemli değildir.)

 @HotSpotIntrinsicCandidate public native int hashCode(); 

Ne zaman equals()ve hashcode()yöntemler geçersiz değildir, yukarıdaki yöntemler yerine çağrılan göreceksiniz. Bu durumda, yöntemler gerçek amacını yerine getirmek değildir equals()ve hashcode()iki veya daha fazla nesnenin aynı değerlere sahip olup olmadığını kontrol etmektir.

Kural olarak, geçersiz kıldığınızda, geçersiz kılmanız equals()da gerekir hashcode().

Eşittir () ile nesneleri karşılaştırma

Bu equals()yöntemi Java'daki nesneleri karşılaştırmak için kullanıyoruz . İki nesnenin aynı olup olmadığını belirlemek equals()için, nesnelerin niteliklerinin değerlerini karşılaştırır:

 public class EqualsAndHashCodeExample { public static void main(String... equalsExplanation) { System.out.println(new Simpson("Homer", 35, 120) .equals(new Simpson("Homer",35,120))); System.out.println(new Simpson("Bart", 10, 120) .equals(new Simpson("El Barto", 10, 45))); System.out.println(new Simpson("Lisa", 54, 60) .equals(new Object())); } static class Simpson { private String name; private int age; private int weight; public Simpson(String name, int age, int weight) { this.name = name; this.age = age; this.weight = weight; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Simpson simpson = (Simpson) o; return age == simpson.age && weight == simpson.weight && name.equals(simpson.name); } } } 

İlk karşılaştırmada, equals()geçerli nesne örneğini geçirilen nesneyle karşılaştırır. İki nesne aynı değerlere sahipse equals()geri dönecektir true.

İkinci karşılaştırmada, equals()aktarılan nesnenin boş olup olmadığını veya farklı bir sınıf olarak yazılıp yazılmadığını kontrol eder . Farklı bir sınıfsa, nesneler eşit değildir.

Son olarak, equals()nesnelerin alanlarını karşılaştırır. İki nesne aynı alan değerlerine sahipse, nesneler aynıdır.

Nesne karşılaştırmalarını analiz etme

Şimdi bu karşılaştırmaların sonuçlarını bizim main()yöntemimizde inceleyelim. İlk olarak, iki Simpsonnesneyi karşılaştırıyoruz :

 System.out.println(new Simpson("Homer", 35, 120).equals(new Simpson("Homer", 35, 120))); 

Buradaki nesneler aynıdır, dolayısıyla sonuç olacaktır true.

Sonra, iki Simpsonnesneyi tekrar karşılaştırıyoruz :

 System.out.println(new Simpson("Bart", 10, 45).equals(new Simpson("El Barto", 10, 45))); 

Buradaki nesneler neredeyse aynı ama isimleri farklı: Bart ve El Barto. Bu nedenle sonuç olacaktır false.

Son olarak, bir Simpsonnesneyi ve Object sınıfının bir örneğini karşılaştıralım :

 System.out.println(new Simpson("Lisa", 54, 60).equals(new Object())); 

Bu durumda sonuç false, sınıf türlerinin farklı olmasından kaynaklanacaktır .

eşittir () ve ==

İlk bakışta, ==operatör ve equals()yöntem aynı şeyi yapıyor gibi görünebilir, ancak gerçekte farklı çalışırlar. ==Operatör iki nesne referanslar aynı nesneyi işaret olup karşılaştırır. Örneğin:

 System.out.println(homer == homer2); 

İlk karşılaştırmada, operatörü Simpsonkullanarak iki farklı örnek oluşturduk new. Bu nedenle, değişkenler homerve bellek yığınındaki homer2farklı Objectreferanslara işaret edecektir . falseSonuç olarak bizde olacak .

System.out.println(homer.equals(homer2)); 

İkinci karşılaştırmada, equals()yöntemi geçersiz kılıyoruz. Bu durumda sadece isimler karşılaştırılacaktır. Her iki Simpsonnesnenin adı da "Homer" olduğu için sonuç olacaktır true.

Hashcode () ile nesneleri benzersiz şekilde tanımlama

hashcode()Nesneleri karşılaştırırken performansı optimize etmek için yöntemi kullanıyoruz . Yürütme   hashcode(), programınızdaki her nesne için benzersiz bir kimlik döndürür, bu da nesnenin tüm durumunu karşılaştırma görevini çok daha kolay hale getirir.

Bir nesnenin karma kodu başka bir nesnenin karma kodu ile aynı değilse, equals()yöntemi yürütmek için bir neden yoktur : yalnızca iki nesnenin aynı olmadığını bilirsiniz. Karma kodudur Öte yandan, olduğu aynı, o zaman yürütme gerekir equals()değerler ve alanlar aynı olup olmadığını belirlemek için bir yöntem.

İşte pratik bir örnek hashcode().

 public class HashcodeConcept { public static void main(String... hashcodeExample) { Simpson homer = new Simpson(1, "Homer"); Simpson bart = new Simpson(2, "Homer"); boolean isHashcodeEquals = homer.hashCode() == bart.hashCode(); if (isHashcodeEquals) { System.out.println("Should compare with equals method too."); } else { System.out.println("Should not compare with equals method because " + "the id is different, that means the objects are not equals for sure."); } } static class Simpson { int id; String name; public Simpson(int id, String name) { this.id = id; this.name = name; } @Override public boolean equals(Object o)  if (this == o) return true; if (o == null  @Override public int hashCode() { return id; } } } 

Her hashcode()zaman aynı değeri döndüren A geçerlidir ancak çok etkili değildir. Bu durumda karşılaştırma her zaman geri dönecektir true, dolayısıyla equals()yöntem her zaman çalıştırılacaktır. Bu durumda performans artışı yoktur.  

Koleksiyonlarla eşittir () ve karma kod () kullanma

SetArayüz eklenecektir yinelenen unsurları sağlamaktan sorumludur Setalt sınıf. Aşağıda, Setarayüzü uygulayan sınıflardan bazıları verilmiştir :

  • HashSet
  • Ağaç Kümesi
  • LinkedHashSet
  • CopyOnWriteArraySet

A'ya yalnızca benzersiz öğeler eklenebilir Set, bu nedenle HashSetsınıfa bir öğe eklemek istiyorsanız (örneğin), öğenin benzersiz olduğunu doğrulamak için önce equals()ve hashcode()yöntemlerini kullanmanız gerekir . Bu durumda equals()ve hashcode()yöntemleri geçersiz kılınmazsa, koda yinelenen öğeler ekleme riskiyle karşılaşırsınız.

Aşağıdaki kodda, addbir HashSetnesneye yeni bir öğe eklemek için yöntemi kullanıyoruz . Yeni öğe eklenmeden önce, öğenin HashSetverilen koleksiyonda zaten var olup olmadığını kontrol eder:

 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; 

If the object is the same, the new element won’t be inserted.

Hash collections

Set isn’t the only collection that makes use of equals() and hashcode(). HashMap, Hashtable, and LinkedHashMap also require these methods. As a rule, if you see a collection that has the prefix of “Hash,” you can be sure that it requires overriding the hashcode() and equals() methods to make their features work properly.  

Guidelines for using equals() and hashcode()

You should only execute an equals() method for objects that have the same unique hashcode ID. You should not execute equals() when the hashcode ID is different.

Table 1. Hashcode comparisons

If the hashcode() comparison ... Then …
returns true execute equals()
returns false do not execute equals()

This principle is mainly used in Set or Hash collections for performance reasons.

Rules for object comparison

When a hashcode() comparison returns false, the equals() method must also return false. If the hashcode is different, then the objects are definitely not equal.

Table 2. Object comparison with hashcode()

When the hashcode comparison returns ... The equals() method should return ...
true true or false
false false

When the equals() method returns true, it means that the objects are equal in all values and attributes. In this case,  the hashcode comparison must be true as well.

Table 3. Object comparison with equals()

When the equals() method returns ... The hashcode() method should return ...
true true
false true or false

Take the equals() and hashcode() challenge!

It’s time to test your skills with the equals() and hashcode() methods.  Your goal in this challenge is to figure out the output of the two equals() method comparisons and guess the size of the Set collection.

To start, study the following code carefully:

 public class EqualsHashCodeChallenge { public static void main(String... doYourBest) { System.out.println(new Simpson("Bart").equals(new Simpson("Bart"))); Simpson overriddenHomer = new Simpson("Homer") { public int hashCode() { return (43 + 777) + 1; } }; System.out.println(new Simpson("Homer").equals(overriddenHomer)); Set set = new HashSet(Set.of(new Simpson("Homer"), new Simpson("Marge"))); set.add(new Simpson("Homer")); set.add(overriddenHomer); System.out.println(set.size()); } static class Simpson { String name; Simpson(String name) { this.name = name; } @Override public boolean equals(Object obj) { Simpson otherSimpson = (Simpson) obj; return this.name.equals(otherSimpson.name) && this.hashCode() == otherSimpson.hashCode(); } @Override public int hashCode() { return (43 + 777); } } } 

Remember, analyze the code first, guess the result, and then run the code. Your goal is to improve your skill with code analysis and absorb core Java concepts to make your code more powerful. Choose your answer before checking the correct answer below.

 A) true true 4 B) true false 3 C) true false 2 D) false true 3 

What just happened? Understanding equals() and hashcode()

In the first equals() method comparison, the result is true because the state of the object is exactly the same and the hashcode() method returns the same value for both objects.

In the second equals() method comparison, the hashcode() method is being overridden for the overridenHomer variable. The name is “Homer” for both Simpson objects, but the hashcode() method returns a different value for overriddenHomer. In this case, the final result from the the equals() method will be false because the method contains a comparison with the hashcode.

You might notice that the size of the collection is set to hold three Simpson objects. Let’s check this in a detailed way.

The first object in the set will be will be inserted normally:

 new Simpson("Homer"); 

The next object will be inserted normally, as well, because it holds a different value from the previous object:

 new Simpson("Marge"); 

Finally,  the following Simpson object has the same value as the first object. In this case the object won’t be inserted:

 set.add(new Simpson("Homer")); 

Bildiğimiz gibi, overridenHomernesne normal Simpson(“Homer”)somutlaştırmadan farklı bir hashcode değeri kullanır . Bu nedenle, bu öğe koleksiyona eklenecek:

 overriddenHomer; 

Cevap anahtarı

Bu Java meydan okuyucusunun cevabı B'dir . Çıktı şu şekilde olacaktır:

 true false 3 

Video yarışması! Hata ayıklama eşittir () ve karma kod ()

Hata ayıklama, programlama kavramlarını tamamen özümsemenin ve aynı zamanda kodunuzu geliştirmenin en kolay yollarından biridir. Bu videoda, ben Java equals()ve hashcode()meydan okuma ile ilgili hata ayıklama ve açıklama aşamalarını takip edebilirsiniz .