Sobes.tech
Middle

გთხოვთ, ისაუბროთ Java-ში hashCode და equals მეთოდების კონტრაქტზე.

sobes.tech AI

პასუხი AI-სგან

Java-да hashCode жана equals методдорунун келишими алардын өз ара байланышын аныктайт жана коллекциялардын, негизделген хеш-таблицаларга (мисалы, HashSet, HashMap) колдонулганда объекттердин туура иштешин камсыздайт:

Негизги эрежелер:

  1. Рефлексивдүүлүк: Ар бир нөлдөн башка шилтемелүү мааниге x, x.equals(x) чын болушу керек.
  2. Симметриялыктык: Ар бир нөлдөн башка шилтемелүү маанилер x жана y үчүн, x.equals(y) чын болсо, анда y.equals(x) да чын болушу керек.
  3. Транзитивдүүлүк: Ар бир нөлдөн башка шилтемелүү маанилер x, y жана z үчүн, эгер x.equals(y) жана y.equals(z) чын болсо, анда x.equals(z) да чын болушу керек.
  4. Туруктуулук: Ар бир нөлдөн башка шилтемелүү маанилер x жана y үчүн, көп жолу чакырылган x.equals(y) бирдей натыйжа бериши керек, эгер x жана y өзгөртүлбөсө.
  5. Нөл эмес маанилер: Ар бир нөлдөн башка шилтемелүү мааниге x үчүн, x.equals(null) жок болушу керек.

Жана негизги эрежеде, hashCode жана equals байланышы:

  • Эгер эки объект equals(Object) боюнча барабар болсо, алардын hashCode() методдору бирдей бүтүн санды чыгарышы керек.
  • Ооба эмес: эгер эки объекттин хеш-коду бирдей болсо, бул алардын барабар экенин билдирбейт.

Контракттын мааниси:

Контракттын бузулушу коллекциялардын туура иштешине алып келиши мүмкүн. Мисалы, эгер эки барабар объект ар башка хеш-коддорду кайтарса, HashMap аларды ар башка "корзиналарга" (buckets) жайгаштыра алат жана бири-бирин таба албай калат, эгер логикалык жактан барабар болсо дагы.

Туура ишке ашырылган мисал:

// Туура `equals` жана `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; // Магическое число, обычно простое
        result = 31 * result + x;
        result = 31 * result + y;
        return result;
    }

    // Геттеры (необязательно для примера equals/hashCode)
    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }
}

Использование:

  • Всегда переопределяйте оба метода (equals и hashCode) вместе.
  • При вычислении hashCode используйте те же поля, которые используются в equals.
  • Старайтесь создавать "хорошие" хеш-функции, которые равномерно распределяют хеш-коды, чтобы минимизировать коллизии (когда разные объекты имеют одинаковый хеш-код) и улучшить производительность хешированных коллекций.
  • Для примитивов используйте их значения. Для объектов вызывайте их hashCode(). Для массивов используйте методы из Arrays.

В Java 7+ для удобства и корректности рекомендуется использовать Objects.equals(Object a, Object b) и Objects.hash(Object... values).

Пример с Objects:

// Пример класса с equals и hashCode с использованием 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; // Логика сравнения остаётся
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y); // Удобный метод для вычисления хеша
    }
}