Java-objecten vergelijken met equals () en hashcode ()

In deze Java Challenger leert u hoe equals()en hashcode()combineert u objectvergelijkingen in uw Java-programma's efficiënt en gemakkelijk. Simpel gezegd, deze methoden werken samen om te controleren of twee objecten dezelfde waarden hebben.  

Zonder equals()en hashcode()zouden we zeer grote " if" vergelijkingen moeten maken door elk veld van een object te vergelijken. Dit zou de code erg verwarrend en moeilijk te lezen maken. Samen helpen deze twee methoden ons om meer flexibele en samenhangende code te creëren.

Download de broncode van Java Challengers.

Het overschrijven is gelijk aan () en hashcode () in Java

Methode overschrijven is een techniek waarbij het gedrag van de bovenliggende klasse of interface opnieuw wordt geschreven (overschreven) in de subklasse om te profiteren van polymorfisme. Elke Objectin Java bevat een equals()en een hashcode()methode, maar deze moeten worden overschreven om correct te werken.

Om te begrijpen hoe overschrijven werkt met equals()en   hashcode(), kunnen we hun implementatie in de kern Java-klassen bestuderen. Hieronder staat de equals()methode in de Objectklas. De methode controleert of het huidige exemplaar hetzelfde is als het eerder doorgegeven exemplaar Object.

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

Als de hashcode()methode niet wordt overschreven, wordt de standaardmethode in de Objectklasse aangeroepen. Dit is een native methode , wat betekent dat het wordt uitgevoerd in een andere taal zoals C, en een code retourneert met betrekking tot het geheugenadres van het object. (Het is niet zo belangrijk om precies te weten hoe deze methode werkt, tenzij u JDK-code schrijft.)

 @HotSpotIntrinsicCandidate public native int hashCode(); 

Wanneer de equals()en hashcode()methoden niet worden overschreven, ziet u de bovenstaande methoden aangeroepen plaats. In dit geval voldoen de methoden niet aan het werkelijke doel van equals()en hashcode(), namelijk controleren of twee of meer objecten dezelfde waarden hebben.

In de regel moet u bij overschrijven equals()ook overschrijven hashcode().

Objecten vergelijken met is gelijk aan ()

We gebruiken de equals()methode om objecten in Java te vergelijken. Om te bepalen of twee objecten hetzelfde zijn, equals()vergelijkt u de waarden van de attributen van de objecten:

 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); } } } 

In de eerste vergelijking wordt equals()de huidige objectinstantie vergeleken met het object dat is doorgegeven. Als de twee objecten dezelfde waarden hebben, equals()zal terugkeren true.

In de tweede vergelijking wordt equals()gecontroleerd of het doorgegeven object null is , of dat het als een andere klasse is getypt. Als het een andere klasse is, zijn de objecten niet gelijk.

equals()Vergelijkt ten slotte de velden van de objecten. Als twee objecten dezelfde veldwaarden hebben, zijn de objecten hetzelfde.

Objectvergelijkingen analyseren

Laten we nu de resultaten van deze vergelijkingen in onze main()methode bekijken. Eerst vergelijken we twee Simpsonobjecten:

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

De objecten hier zijn identiek, dus het resultaat zal zijn true.

Vervolgens vergelijken we twee Simpsonobjecten opnieuw:

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

De objecten hier zijn bijna identiek maar hun namen zijn verschillend: Bart en El Barto. Daarom zal het resultaat zijn false.

Laten we tot slot een Simpsonobject en een instantie van de klasse Object vergelijken:

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

In dit geval zal het resultaat zijn falsedat de klassetypes verschillend zijn.

is gelijk aan () versus ==

Op het eerste gezicht lijken de ==operator en de equals()methode hetzelfde te doen, maar in werkelijkheid werken ze anders. De ==operator vergelijkt of twee objectreferenties naar hetzelfde object verwijzen. Bijvoorbeeld:

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

In de eerste vergelijking hebben we twee verschillende Simpsoninstanties gemaakt met behulp van de newoperator. Hierdoor zullen de variabelen homeren homer2verwijzen naar verschillende Objectverwijzingen in de geheugenheap. Dus we hebben falseals resultaat.

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

In de tweede vergelijking overschrijven we de equals()methode. In dit geval worden alleen de namen vergeleken. Omdat de naam van beide Simpsonobjecten "Homer" is, zal het resultaat zijn true.

Uniek identificeren van objecten met hashcode ()

We gebruiken de hashcode()methode om de prestaties te optimaliseren bij het vergelijken van objecten. Uitvoeren   hashcode()retourneert een unieke ID voor elk object in uw programma, wat het vergelijken van de hele staat van het object veel gemakkelijker maakt.

Als de hashcode van een object niet hetzelfde is als de hashcode van een ander object, is er geen reden om de equals()methode uit te voeren : je weet gewoon dat de twee objecten niet hetzelfde zijn. Aan de andere kant, als de hashcode is hetzelfde, dan moet je de execute equals()methode om te bepalen of de waarden en velden zijn hetzelfde.

Hier is een praktisch voorbeeld met 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; } } } 

Een hashcode()die altijd dezelfde waarde retourneert, is geldig maar niet erg effectief. In dit geval zal de vergelijking altijd terugkeren true, dus de equals()methode wordt altijd uitgevoerd. In dit geval is er geen prestatieverbetering.  

Equals () en hashcode () gebruiken met verzamelingen

De Setinterface is ervoor verantwoordelijk dat er geen dubbele elementen in een Setsubklasse worden ingevoegd . De volgende zijn enkele van de klassen die de Setinterface implementeren :

  • HashSet
  • TreeSet
  • LinkedHashSet
  • CopyOnWriteArraySet

Alleen unieke elementen kunnen in a worden ingevoegd Set, dus als u een element aan de HashSetklasse wilt toevoegen (bijvoorbeeld), moet u eerst de methoden equals()en hashcode()gebruiken om te verifiëren dat het element uniek is. Als de methoden equals()en hashcode()in dit geval niet worden overschreven, loopt u het risico dubbele elementen in de code in te voegen.

In de onderstaande code gebruiken we de addmethode om een ​​nieuw element aan een HashSetobject toe te voegen . Voordat het nieuwe element wordt toegevoegd, wordt HashSetgecontroleerd of het element al bestaat in de gegeven verzameling:

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

Als het object hetzelfde is, wordt het nieuwe element niet ingevoegd.

Hash-collecties

Setis niet de enige collectie die gebruik maakt van equals()en hashcode(). HashMap, Hashtable en LinkedHashMap vereisen ook deze methoden. Als u een verzameling ziet met het voorvoegsel 'Hash', kunt u er in de regel zeker van zijn dat de methoden hashcode()en moeten worden overschreven equals()om hun functies correct te laten werken.  

Richtlijnen voor het gebruik van equals () en hashcode ()

equals()Voer een methode alleen uit voor objecten die dezelfde unieke hashcode-ID hebben. U moet niet uitvoeren equals()als de hashcode-ID anders is.

Tabel 1. Hashcode-vergelijkingen

Als de hashcode()vergelijking ... Vervolgens …
geeft true terug uitvoeren equals()
geeft false terug voer niet uit 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")); 

Zoals we weten, gebruikt het overridenHomerobject een andere hashcode-waarde dan de normale Simpson(“Homer”)instantiatie. Om deze reden wordt dit element in de collectie ingevoegd:

 overriddenHomer; 

Antwoord sleutel

Het antwoord op deze Java uitdager is B . De output zou zijn:

 true false 3 

Video-uitdaging! Foutopsporing is gelijk aan () en hashcode ()

Foutopsporing is een van de gemakkelijkste manieren om programmeerconcepten volledig op te nemen en tegelijkertijd uw code te verbeteren. In deze video kun je meekijken terwijl ik debuggen en de Java equals()en hashcode()challenge uitleg.