JavaRush /Java Blog /Random-IT /Pausa caffè #168. Perché sovrascrivere i metodi equals e ...

Pausa caffè #168. Perché sovrascrivere i metodi equals e hashcode in Java?

Pubblicato nel gruppo Random-IT

Perché sovrascrivere i metodi equals e hashcode in Java?

Fonte: Medium Questo articolo si concentra su due metodi strettamente correlati: equals() e hashcode() . Imparerai come interagiscono tra loro e come sovrascriverli correttamente. Pausa caffè #168.  Perché sovrascrivere i metodi equals e hashcode in Java?  -1

Perché sovrascriviamo il metodo equals()?

In Java, non possiamo sovraccaricare il comportamento di operatori come == , += , -+ . Funzionano secondo un determinato processo. Consideriamo ad esempio il funzionamento dell'operatore == .

Come funziona l'operatore ==?

Controlla se i due riferimenti confrontati puntano alla stessa istanza in memoria. L' operatore == valuterà true solo se i due riferimenti rappresentano la stessa istanza in memoria. Diamo un'occhiata al codice di esempio:
public class Person {
      private Integer age;
      private String name;

      ..getters, setters, constructors
      }
Diciamo che nel tuo programma hai creato due oggetti Persona in posti diversi e vuoi confrontarli.
Person person1 = new Person("Mike", 34);
Person person2 = new Person("Mike", 34);
System.out.println( person1 == person2 ); --> will print false!
Dal punto di vista aziendale, i due sembrano uguali, giusto? Ma per la JVM non sono la stessa cosa. Poiché entrambe vengono create utilizzando la parola chiave new , queste istanze si trovano in segmenti di memoria diversi. Pertanto l' operatore == restituirà false . Ma se non possiamo sovrascrivere l' operatore == , allora come diciamo alla JVM che vogliamo che questi due oggetti siano trattati allo stesso modo? È qui che entra in gioco il metodo .equals() . Puoi sovrascrivere equals() per verificare se alcuni oggetti hanno gli stessi valori per determinati campi in modo da considerarli uguali. Puoi scegliere quali campi confrontare. Se diciamo che due oggetti Person saranno uguali solo se hanno la stessa età e lo stesso nome, allora l'IDE genererà qualcosa di simile per creare automaticamente equals() :
@Override
public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                name.equals(person.name);
    }
Torniamo al nostro esempio precedente.
Person person1 = new Person("Mike", 34);
Person person2 = new Person("Mike", 34);
System.out.println ( person1 == person2 ); --> will print false!
System.out.println ( person1.equals(person2) ); --> will print true!
Sì, non possiamo sovraccaricare l' operatore == per confrontare gli oggetti nel modo che vogliamo, ma Java ci offre un altro modo: il metodo equals() , che possiamo sovrascrivere come desideriamo. Tieni presente che se non forniamo la nostra versione personalizzata di .equals() (nota anche come override) nella nostra classe, allora .equals() predefinito dalla classe Object e l' operatore == si comporteranno allo stesso modo. Il metodo equals() predefinito , ereditato da Object , controllerà se entrambe le istanze confrontate sono le stesse in memoria!

Perché stiamo sovrascrivendo il metodo hashCode()?

Alcune strutture dati in Java, come HashSet e HashMap , memorizzano i propri elementi in base a una funzione hash applicata a tali elementi. La funzione hash è hashCode() . Se possiamo scegliere di sovrascrivere il metodo .equals() , allora dovremmo avere anche la possibilità di sovrascrivere il metodo hashCode() . C'è una ragione per questo. Dopotutto, l'implementazione predefinita di hashCode() , ereditata da Object , considera unici tutti gli oggetti in memoria! Ma torniamo a queste strutture di dati hash. Esiste una regola per queste strutture dati. Un HashSet non può contenere valori duplicati e una HashMap non può contenere chiavi duplicate. Un HashSet viene implementato utilizzando una HashMap in modo tale che ogni valore HashSet venga archiviato come chiave in HashMap . Come funziona HashMap ? HashMap è un array nativo con più segmenti. Ogni segmento ha un elenco collegato ( linkedList ). Questo elenco collegato memorizza le nostre chiavi. HashMap trova la linkedList corretta per ciascuna chiave utilizzando il metodo hashCode() , quindi scorre tutti gli elementi di quella linkedList e applica il metodo equals() a ciascuno di questi elementi per verificare se quell'elemento è contenuto lì. Non sono ammesse chiavi duplicate. Pausa caffè #168.  Perché sovrascrivere i metodi equals e hashcode in Java?  - 2Quando inseriamo qualcosa in una HashMap , la chiave viene memorizzata in uno di questi elenchi collegati. In quale elenco collegato verrà archiviata questa chiave viene mostrato dal risultato del metodo hashCode() per quella chiave. Cioè, se key1.hashCode() restituisce 4, allora key1 verrà archiviato nel quarto segmento dell'array nella LinkedList esistente lì . Per impostazione predefinita, il metodo hashCode() restituisce risultati diversi per ciascuna istanza. Se abbiamo un equals() predefinito che si comporta come == , trattando tutte le istanze in memoria come oggetti diversi, allora non ci saranno problemi. Come ricorderete, nel nostro esempio precedente abbiamo detto che vogliamo che le istanze di Person siano considerate uguali se la loro età e i loro nomi sono gli stessi.
Person person1 = new Person("Mike", 34);
    Person person2 = new Person("Mike", 34);
    System.out.println ( person1.equals(person2) );  --> will print true!
Ora creiamo una mappa per archiviare queste istanze come chiavi con una stringa specifica come coppia di valori.
Map<Person, String> map = new HashMap();
map.put(person1, "1");
map.put(person2, "2");
Nella classe Person , non abbiamo sovrascritto il metodo hashCode , ma abbiamo un metodo equals sovrascritto . Poiché l' hashCode predefinito fornisce risultati diversi per diverse istanze Java di person1.hashCode() e person2.hashCode() , ci sono alte probabilità di ottenere risultati diversi. La nostra mappa può terminare con persone diverse in diversi elenchi collegati. Pausa caffè #168.  Perché sovrascrivere i metodi equals e hashcode in Java?  - 3Questo va contro la logica di HashMap . Dopotutto, una HashMap non può avere più chiavi identiche! Il punto è che l' hashCode() predefinito ereditato dalla classe Object non è sufficiente. Anche dopo aver sovrascritto il metodo equals() della classe Person . Ecco perché dobbiamo sovrascrivere il metodo hashCode() dopo aver sovrascritto il metodo equals . Ora risolviamo questo problema. Dobbiamo sovrascrivere il nostro metodo hashCode() in modo che prenda in considerazione gli stessi campi di equals() , ovvero age e name .
public class Person {
      private Integer age;
      private String name;

      ..getters, setters, constructors
@Override
public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                name.equals(person.name);
    }
@Override
public int hashCode() {
        int prime = 31;
        return prime*Objects.hash(name, age);
    }
Nel metodo hashCode() abbiamo utilizzato un valore semplice (puoi utilizzare qualsiasi altro valore). Tuttavia, si suggerisce di utilizzare numeri primi per creare meno problemi. Proviamo di nuovo a memorizzare queste chiavi nella nostra HashMap :
Map<Person, String> map = new HashMap();
map.put(person1, "1");
map.put(person2, "2");
person1.hashCode() e person2.hashCode() saranno gli stessi. Diciamo che sono 0. La HashMap andrà al segmento 0 e in esso la LinkedList salverà persona1 come chiave con il valore “1”. Nel secondo caso, quando HashMap va nuovamente al bucket 0 per memorizzare la chiave person2 con il valore “2”, vedrà che lì esiste già un’altra chiave uguale ad essa. In questo modo sovrascriverà la chiave precedente. E solo la chiave person2 esisterà nella nostra HashMap . Ecco come abbiamo imparato come funziona la regola HashMap , che afferma che non è possibile utilizzare più chiavi identiche! Tuttavia, tieni presente che istanze diverse possono avere lo stesso hashcode e istanze uguali devono restituire lo stesso hashcode.Pausa caffè #168.  Perché sovrascrivere i metodi equals e hashcode in Java?  - 4
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION