Sobes.tech
Middle

Povedzte o zmluve metód hashCode a equals v Jave.

sobes.tech AI

Odpoveď od AI

Dohoda metód hashCode a equals v Jave určuje ich vzťah a zabezpečuje správne správanie objektov pri používaní kolekcií založených na hash tabuľkách (napríklad HashSet, HashMap).

Hlavné pravidlá dohody:

  1. Reflexivita: Pre akúkoľvek nenulovú referenciu x musí x.equals(x) vracať true.
  2. Symetria: Pre akékoľvek nenulové referencie x a y musí platiť, že x.equals(y) vracia true ak a len ak y.equals(x) vracia true.
  3. Transitivita: Pre akékoľvek nenulové referencie x, y a z, ak x.equals(y) a y.equals(z)true, potom x.equals(z) musí byť true.
  4. Konzistentnosť: Pre akékoľvek nenulové referencie x a y, opakované volanie x.equals(y) pri rovnakých objektoch musí vždy vracať rovnaký výsledok.
  5. Null: Pre akúkoľvek nenulovú referenciu x, x.equals(null) musí vracať false.

A hlavné pravidlo spájajúce hashCode a equals:

  • Ak sú dva objekty rovné podľa metódy equals(Object), potom volanie hashCode() na každom z týchto objektov musí produkovať rovnaké celé číslo.
  • Opak je ne-pravdivý: ak majú dva objekty rovnaký hash kód, neznamená to, že sú rovnaké.

Hodnota dohody:

Porušenie dohody môže viesť k nesprávnemu správaniu kolekcií. Napríklad, ak dva rovné objekty vracajú odlišné hash kódy, HashMap ich môže umiestniť do rôznych "košov" a nebude ich vedieť nájsť podľa druhého, aj keď sú logicky rovnaké.

Príklad správnej implementácie:

// Príklad triedy so správnymi `equals` a `hashCode`
public final class Point {
    private final int x;
    private final int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Point point = (Point) o;
        return x == point.x && y == point.y;
    }

    @Override
    public int hashCode() {
        int result = 17; // Magické číslo, zvyčajne prvočíslo
        result = 31 * result + x;
        result = 31 * result + y;
        return result;
    }

    // Gettery (nepovinné pre `equals`/`hashCode`)
    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }
}

Použitie:

  • Vždy prepísať obe metódy (equals a hashCode) spolu.
  • Pri výpočte hashCode používať tie isté polia, ktoré sa používajú v equals.
  • Snažiť sa vytvárať "dobré" hash funkcie, ktoré rovnomerne rozdeľujú hash kódy, aby minimalizovali kolízie (keď rôzne objekty majú rovnaký hash kód) a zlepšili výkon hashovaných kolekcií.
  • Pre primitívy používať ich hodnoty. Pre objekty volať ich hashCode(). Pre polia používať metódy z Arrays.

V Java 7+ je odporúčané používať Objects.equals(Object a, Object b) a Objects.hash(Object... values) pre jednoduchšiu a správnu implementáciu.

Príklad s Objects:

// Príklad triedy s `equals` a `hashCode` s použitím `Objects`
import java.util.Objects;

public final class PointWithObjects {
    private final int x;
    private final int y;

    public PointWithObjects(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        PointWithObjects that = (PointWithObjects) o;
        return x == that.x && y == that.y; // Logika porovnania ostáva
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y); // Pohodlná metóda na výpočet hash
    }
}