Sobes.tech
Middle

Meséljen a hashCode és equals metódusok szerződéséről Java-ban.

sobes.tech MI

Válasz az MI-től

A hashCode és equals metódusok Java-ban meghatározzák azok kapcsolatát, és garantálják az objektumok helyes viselkedését a hash-alapú kollekciók használatakor (például HashSet, HashMap).

A szerződés fő szabályai:

  1. Reflexivitás: Bármely nem null hivatkozási érték x esetén, x.equals(x)-nek true-t kell visszaadnia.
  2. Szimmetria: Bármely nem null x és y hivatkozási érték esetén, x.equals(y) akkor és csak akkor true, ha y.equals(x) is true.
  3. Tranzitivitás: Bármely nem null x, y és z esetén, ha x.equals(y) és y.equals(z) true, akkor x.equals(z) is true.
  4. Konzisztencia: Bármely nem null x és y esetén, az x.equals(y) többszöri hívása ugyanazt az eredményt kell, hogy adja, amennyiben x és y nem változnak.
  5. Null nem egyenlőség: Bármely nem null x esetén, x.equals(null)-nak false-t kell visszaadnia.

És a fő szabály, ami összeköti a hashCode-ot és az equals-t:

  • Ha két objektum egyenlő az equals(Object) módszer szerint, akkor ezek hashCode() hívásának eredménye ugyanaz a szám kell, hogy legyen.
  • Fordítva nem igaz: ha két objektumnak ugyanaz a hash-kódja, az nem jelenti, hogy egyenlőek.

A szerződés értéke:

A szerződés megsértése helytelen működést eredményezhet a kollekciókban. Például, ha két egyenlő objektum különböző hash-kódokat ad vissza, a HashMap külön "kosarakba" helyezheti őket, és nem találhatja meg az egyik objektumot a másik alapján, még akkor sem, ha logikailag egyenlőek.

Példa helyes megvalósításra:

// Példa osztály helyes `equals` és `hashCode`-szal
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; // Bűvös szám, általában prímszám
        result = 31 * result + x;
        result = 31 * result + y;
        return result;
    }

    // Getter-ek (nem kötelező az `equals`/`hashCode` példához)
    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }
}

Használat:

  • Mindig felülírni mindkét metódust (equals és hashCode) együtt.
  • A hashCode kiszámításakor ugyanazokat a mezőket használja, mint az equals.
  • Próbáljon "jó" hash függvényeket készíteni, amelyek egyenletesen osztják el a hash-kódokat, minimalizálva az ütközéseket (amikor különböző objektumok ugyanazt a hash-kódot kapják), és javítva a hash-alapú kollekciók teljesítményét.
  • Primitívek esetén használja azok értékeit. Objektumok esetén hívja meg a hashCode()-ot. Tömbök esetén használja az Arrays osztály metódusait.

Java 7+ esetén ajánlott az Objects.equals(Object a, Object b) és az Objects.hash(Object... values) használata a kód egyszerűsítése érdekében.

Példa az Objects-szel:

// Osztály példa `equals` és `hashCode`-szal az `Objects` használatával
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; // A összehasonlítás logikája változatlan
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y); // Kényelmes módszer a hash kiszámítására
    }
}