Object.equals în Java

equals() spune dacă două obiecte sunt „egale”, iar hashCode() dă un număr folosit de HashMap și HashSet; se suprascriu împreună.

Sintaxă
boolean equals(Object obj)
int hashCode()

Ce face Object.equals

Implementarea din Object a lui equals compară identitatea: a.equals(b) este adevărat doar dacă a și b sunt același obiect, exact ca a == b. Clasele care reprezintă valori (String, Integer, LocalDate, records) o suprascriu ca să compare conținutul.

hashCode() returnează un int folosit de colecțiile cu hash pentru a găsi rapid un obiect. Regula de aur: dacă a.equals(b), atunci a.hashCode() == b.hashCode(). Când suprascrii equals, trebuie să suprascrii și hashCode (cel mai simplu cu Objects.hash); altfel HashSet și HashMap nu îți mai găsesc obiectele. Varianta implicită a lui hashCode diferă la fiecare rulare.

Un record primește automat equals și hashCode corecte, bazate pe toate componentele.

Parametri

Parametru Descriere
obj Obiectul cu care se compară; poate fi null (rezultat false).

Ce returnează

equals: boolean. hashCode: un int.

Exemple

Exemplul 1: Fără suprascriere: identitate

public class Main {
    static class Oras {
        final String nume;

        Oras(String nume) {
            this.nume = nume;
        }
    }

    public static void main(String[] args) {
        Oras a = new Oras("Iași");
        Oras b = new Oras("Iași");
        Oras c = a;
        System.out.println(a.equals(b));
        System.out.println(a.equals(c));
        System.out.println(a.hashCode() == c.hashCode());
    }
}

Rezultat

false
true
true

Exemplul 2: equals și hashCode suprascrise

Două produse cu același cod sunt egale, iar HashSet păstrează doar unul.

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

public class Main {
    static class Produs {
        final String cod;
        final String nume;

        Produs(String cod, String nume) {
            this.cod = cod;
            this.nume = nume;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (!(o instanceof Produs p)) {
                return false;
            }
            return cod.equals(p.cod);
        }

        @Override
        public int hashCode() {
            return Objects.hash(cod);
        }
    }

    public static void main(String[] args) {
        Produs a = new Produs("P-100", "Cafea");
        Produs b = new Produs("P-100", "Cafea boabe");
        System.out.println(a.equals(b));
        System.out.println(a.hashCode() == b.hashCode());
        Set<Produs> stoc = new HashSet<>();
        stoc.add(a);
        stoc.add(b);
        System.out.println("Produse distincte: " + stoc.size());
        System.out.println(a.equals(null));
    }
}

Rezultat

true
true
Produse distincte: 1
false

Exemplul 3: Un record le are pe amândouă

import java.util.Set;

public class Main {
    record Punct(int x, int y) {}

    public static void main(String[] args) {
        Punct p1 = new Punct(3, 4);
        Punct p2 = new Punct(3, 4);
        System.out.println(p1.equals(p2));
        System.out.println(p1.hashCode() == p2.hashCode());
        System.out.println(Set.of(p1).contains(p2));
    }
}

Rezultat

true
true
true

Greșeli frecvente

  • Suprascrii equals cu parametrul de tip propriu: public boolean equals(Produs p) nu suprascrie, ci supraîncarcă metoda. Parametrul trebuie să fie Object; adnotarea @Override te avertizează.
  • Suprascrii doar equals, fără hashCode: obiectele egale ajung în locuri diferite din HashMap și nu se mai găsesc.
  • Folosești în hashCode câmpuri care se schimbă după ce obiectul a fost pus într-un HashSet: obiectul „se pierde” în set.

Comenzi înrudite

  • equals și hashCode: equals decide când două obiecte sunt „egale” ca valoare; hashCode trebuie rescris împreună cu el, altfel HashMap și HashSet nu funcționează corect.
  • Objects.hash: hash() calculează un cod hash din mai multe câmpuri (ideal în hashCode()); hashCode(o) dă 0 pentru null.
  • Objects: Clasa java.util.Objects are metode statice care lucrează sigur cu null; equals() compară două obiecte care pot fi null.
  • Object: Clasa de bază a tuturor claselor Java; getClass() spune din ce clasă face parte un obiect la rulare.
  • String.equals: Verifică dacă două șiruri au exact același text; equalsIgnoreCase și equalsFoldCase ignoră literele mari/mici.