Programování

Porovnání Java objektů s equals () a hashcode ()

V tomhle Java Challenger naučíte se jak se rovná() a hashcode () zkombinujte, aby bylo porovnání objektů ve vašich programech Java efektivní a snadné. Jednoduše řečeno, tyto metody spolupracují a ověřují, zda mají dva objekty stejné hodnoty.

Bez se rovná() a hashcode () museli bychom vytvořit velmi velké “-li"srovnání, porovnání každého pole z objektu. To by způsobilo, že by kód byl opravdu matoucí a těžko čitelný. Společně nám tyto dvě metody pomohou vytvořit pružnější a soudržnější kód."

Získejte zdrojový kód Java Challengers.

Přepsání equals () a hashcode () v Javě

Přepsání metody je technika, při které se chování nadřazené třídy nebo rozhraní zapíše znovu (přepíše) do podtřídy, aby se využil výhod polymorfismu. Každý Objekt v Javě obsahuje se rovná() a hashcode () Tato metoda musí být přepsána, aby správně fungovala.

Pochopit, jak funguje přepsání se rovná() ahashcode ()můžeme studovat jejich implementaci v základních třídách Java. Níže je se rovná() metoda v Objekt třída. Metoda kontroluje, zda je aktuální instance stejná jako dříve předaná Objekt.

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

Když hashcode () metoda není přepsána, výchozí metoda v Objekt třída bude vyvolána. Tohle je nativní metoda, což znamená, že bude provedeno v jiném jazyce, jako je C, a vrátí nějaký kód týkající se adresy paměti objektu. (Není důležité vědět přesně, jak tato metoda funguje, pokud nepíšete kód JDK.)

 @HotSpotIntrinsicCandidate public native int hashCode (); 

Když se rovná() a hashcode () metody nejsou přepsány, místo toho se zobrazí výše uvedené metody. V tomto případě metody neplní skutečný účel se rovná() a hashcode (), což je kontrola, zda dva nebo více objektů mají stejné hodnoty.

Zpravidla, když přepíšete se rovná() musíte také přepsat hashcode ().

Porovnání objektů s equals ()

Používáme se rovná() metoda pro porovnání objektů v Javě. Chcete-li zjistit, zda jsou dva objekty stejné, se rovná() porovnává hodnoty atributů objektů:

 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 (nový Simpson ("Bart", 10, 120) .equals (nový Simpson ("El Barto", 10, 45))); System.out.println (nový Simpson ("Lisa", 54, 60) .equals (nový objekt ())); } statická třída Simpson {soukromé jméno řetězce; soukromý věk; soukromá int váha; public Simpson (název řetězce, int stáří, int váha) {this.name = name; this.age = věk; this.weight = hmotnost; } @Override public boolean equals (Object o) {if (this == o) {return true; } if (o == null || getClass ()! = o.getClass ()) {return false; } Simpson simpson = (Simpson) o; návratový věk == simpson.age && váha == simpson.weight && name.equals (simpson.name); }}} 

V prvním srovnání se rovná() porovnává aktuální instanci objektu s objektem, který byl předán. Pokud mají dva objekty stejné hodnoty, se rovná() vrátí se skutečný.

Ve druhém srovnání se rovná()zkontroluje, zda je předaný objekt nula, nebo pokud je napsán jako jiná třída. Pokud se jedná o jinou třídu, nejsou si objekty stejné.

Konečně, se rovná() porovnává pole objektů. Pokud dva objekty mají stejné hodnoty pole, pak jsou objekty stejné.

Analýza srovnání objektů

Podívejme se nyní na výsledky těchto srovnání v našem hlavní() metoda. Nejprve porovnáme dva Simpson objekty:

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

Objekty zde jsou identické, takže výsledek bude skutečný.

Dále porovnáme dva Simpson objekty znovu:

 System.out.println (nový Simpson(„Bart“, 10, 45) .equals (nové Simpson(„El Barto“, 10, 45))); 

Objekty jsou téměř totožné, ale jejich jména jsou odlišná: Bart a El Barto. Výsledek tedy bude Nepravdivé.

Nakonec porovnejme a Simpson objekt a instance třídy Object:

 System.out.println (nový Simpson(„Lisa“, 54, 60) .equals (nové Objekt())); 

V takovém případě bude výsledek Nepravdivé protože typy tříd jsou různé.

se rovná () versus ==

Na první pohled == operátor a se rovná() Může se zdát, že metoda dělá totéž, ale ve skutečnosti fungují odlišně. The == operátor porovná, zda dva odkazy na objekty ukazují na stejný objekt. Například:

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

V prvním srovnání jsme vytvořili instance dvou různých Simpson instance používající Nový operátor. Z tohoto důvodu proměnné Homer a homer2 bude ukazovat na jiné Objekt odkazy v haldě paměti. Takže budeme mít Nepravdivé jako výsledek.

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

Ve druhém srovnání přepíšeme se rovná() metoda. V tomto případě budou porovnána pouze jména. Protože jméno obou Simpson objekty je „Homer“, výsledkem bude skutečný.

Jedinečná identifikace objektů pomocí hashcode ()

Používáme hashcode () metoda pro optimalizaci výkonu při porovnávání objektů. Prováděníhashcode () vrací jedinečné ID pro každý objekt ve vašem programu, což výrazně usnadňuje porovnání celého stavu objektu.

Pokud hashcode objektu není stejný jako hashcode jiného objektu, není důvod jej provádět se rovná() metoda: víte, že dva objekty nejsou stejné. Na druhou stranu, pokud je hashcode je totéž, pak musíte provést se rovná() metoda k určení, zda jsou hodnoty a pole stejná.

Zde je praktický příklad s hashcode ().

 public class HashcodeConcept {public static void main (String ... hashcodeExample) {Simpson homer = new Simpson (1, "Homer"); Simpson bart = nový Simpson (2, "Homer"); boolean isHashcodeEquals = homer.hashCode () == bart.hashCode (); if (isHashcodeEquals) {System.out.println ("Mělo by se také srovnávat s metodou equals."); } else {System.out.println ("Nemělo by se to srovnávat s metodou equals, protože" + "je id jiné, to znamená, že objekty nejsou pro jistotu rovnocenné."); }} statická třída Simpson {int id; Název řetězce; 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;}}} 

A hashcode () který vždy vrátí stejnou hodnotu, je platný, ale ne příliš efektivní. V takovém případě se srovnání vždy vrátí skutečný, takže se rovná() metoda bude vždy provedena. V tomto případě nedochází ke zlepšení výkonu.

Používání equals () a hashcode () s kolekcemi

The Soubor Rozhraní je zodpovědné za zajištění toho, že do a. nebudou vloženy žádné duplicitní prvky Soubor podtřída. Následuje několik tříd, které implementují Soubor rozhraní:

  • HashSet
  • Sada stromů
  • LinkedHashSet
  • CopyOnWriteArraySet

Do a. Lze vložit pouze jedinečné prvky Soubor, takže pokud chcete přidat prvek do HashSet třídy (například), musíte nejprve použít se rovná() a hashcode () metody k ověření, že je prvek jedinečný. Pokud se rovná() a hashcode ()metody nebyly v tomto případě přepsány, riskovali byste vložení duplicitních prvků do kódu.

V níže uvedeném kódu používáme přidat metoda pro přidání nového prvku do a HashSet objekt. Před přidáním nového prvku HashSet zkontroluje, zda prvek v dané kolekci již existuje:

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

Pokud je objekt stejný, nový prvek se nevloží.

Hash sbírky

Soubor není jediná kolekce, která využívá se rovná() a hashcode (). HashMap, Hashtable a LinkedHashMap také vyžadují tyto metody. Je pravidlem, že pokud vidíte kolekci, která má předponu „Hash“, můžete si být jisti, že vyžaduje přepsání hashcode () a se rovná() metody, aby jejich funkce fungovaly správně.

Pokyny pro používání equals () a hashcode ()

Měli byste provést pouze se rovná() metoda pro objekty, které mají stejné jedinečné ID hashcode. Měl by jsi ne vykonat se rovná() když je ID hashcode jiné.

Tabulka 1. Porovnání hashcode

Pokud hashcode () srovnání ...Pak …
vrací truevykonat se rovná()
vrátí falsenevykonávat se rovná()

Tento princip se používá hlavně v Soubor nebo Hash sbírky z důvodů výkonu.

Pravidla pro porovnávání objektů

Když hashcode () srovnání se vrací Nepravdivése rovná() metoda musí také vrátit false. Pokud je hashcode jiný, pak objekty rozhodně nejsou stejné.

Tabulka 2. Srovnání objektů s hashcode ()

Když se vrátí porovnání hashcode ...The se rovná() metoda by se měla vrátit ...
skutečnýpravda nebo lež
NepravdivéNepravdivé

Když se rovná() metoda se vrací skutečný, to znamená, že objekty jsou si rovny ve všech hodnotách a atributech. V tomto případě musí být pravdivé i porovnání hashcode.

Tabulka 3. Srovnání objektů s equals ()

Když se rovná() metoda se vrací ...The hashcode () metoda by se měla vrátit ...
skutečnýskutečný
Nepravdivépravda nebo lež

Vezměte výzvu equals () a hashcode ()!

Je čas vyzkoušet si své dovednosti pomocí se rovná() a hashcode () metody. Vaším cílem v této výzvě je zjistit výstup těchto dvou se rovná() porovnání metod a odhad velikosti souboru Soubor sbírka.

Nejprve si pečlivě prostudujte následující kód:

 veřejná třída EqualsHashCodeChallenge {public static void main (String ... doYourBest) {System.out.println (nový Simpson ("Bart"). equals (nový Simpson ("Bart"))); Simpson overriddenHomer = nový Simpson ("Homer") {public int hashCode () {návrat (43 + 777) + 1; }}; System.out.println (nový Simpson ("Homer"). Equals (overriddenHomer)); Set set = new HashSet (Set.of (new Simpson ("Homer"), new Simpson ("Marge"))); set.add (nový Simpson ("Homer")); set.add (overriddenHomer); System.out.println (set.size ()); } statická třída Simpson {název řetězce; Simpson (název řetězce) {this.name = name; } @Override public boolean equals (Object obj) {Simpson otherSimpson = (Simpson) obj; vrátit this.name.equals (otherSimpson.name) && this.hashCode () == otherSimpson.hashCode (); } @Override public int hashCode () {return (43 + 777); }}} 

Pamatujte, že nejprve analyzujte kód, hádejte výsledek, a poté spusťte kód. Vaším cílem je zlepšit své dovednosti pomocí analýzy kódu a absorbovat základní koncepty Java, aby byl váš kód výkonnější. Než zkontrolujete správnou odpověď níže, vyberte svou odpověď.

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

Co se právě stalo? Pochopení equals () a hashcode ()

Zaprvé se rovná() Výsledkem je porovnání metody skutečný protože stav objektu je přesně stejný a hashcode () metoda vrátí stejnou hodnotu pro oba objekty.

Ve druhém se rovná() porovnání metody, hashcode () metoda je přepsána pro přepsat Homera proměnná. Název pro oba je „Homer“ Simpson objekty, ale hashcode () metoda vrací jinou hodnotu pro přepsánoHomer. V tomto případě konečný výsledek z se rovná() metoda bude Nepravdivé protože metoda obsahuje srovnání s hashcode.

Můžete si všimnout, že velikost kolekce je nastavena na tři Simpson předměty. Podívejme se na to podrobně.

První objekt v sadě bude vložen normálně:

 nový Simpson („Homer“); 

Další objekt bude vložen také normálně, protože obsahuje jinou hodnotu než předchozí objekt:

 nový Simpson („Marge“); 

Nakonec následující Simpson objekt má stejnou hodnotu jako první objekt. V takovém případě nebude objekt vložen:

 set.add (nový Simpson ("Homer")); 

Jak víme, přepsat Homera objekt používá jinou hodnotu hashcode než normální Simpson („Homer“) instance. Z tohoto důvodu bude tento prvek vložen do kolekce:

 overriddenHomer; 

Odpovědět klíč

Odpověď na tohoto Java challenger je B. Výstup by byl:

 true false 3 

Video výzva! Ladění equals () a hashcode ()

Ladění je jedním z nejjednodušších způsobů, jak plně absorbovat programovací koncepty a zároveň vylepšit váš kód. V tomto videu můžete sledovat, zatímco ladím a vysvětluji Javu se rovná() a hashcode () výzva.

$config[zx-auto] not found$config[zx-overlay] not found