0Pricing
Java Academy · Ders

equals/hashCode Sözleşmesi

İkisinin neden uyumlu olması gerektiği

equals/hashCode Sözleşmesi, CoddyKit'te ücretsiz bir Java Academy dersidir. Bu, 4 dersinin 2. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, Java Academy öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. Java Academy kursu toplamda 4 dersten oluşur.

İki Yöntem, Tek Sözleşme

Her Java nesnesi, equals() ve hashCode() yöntemlerini Object'ten devralır.

Birini yeniden tanımladığınızda, neredeyse her zaman diğerini de yeniden tanımlamanız gerekir. Bu ikisi, hash tabanlı koleksiyonların dayandığı bağlayıcı bir sözleşme oluşturur.

public class Main {
    public static void main(String[] args) {
        Object a = new Object();
        Object b = new Object();
        System.out.println(a.equals(b));
        System.out.println(a.hashCode() == b.hashCode());
    }
}

Temel Kural

Sözleşme şunu belirtir:

  • a.equals(b) doğru ise a.hashCode(), b.hashCode()'a eşit olmalıdır.
  • Hash kodları farklıysa nesnelerin eşit olmadığı garanti edilir.

Eşit nesnelerin hash kodları eşit olmalıdır. Tersi gerekli değildir.

public class Main {
    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "hel" + "lo";
        System.out.println(s1.equals(s2));
        System.out.println(s1.hashCode() == s2.hashCode());
    }
}

Eşit Olmayan Nesneler Aynı Hash'i Paylaşabilir

İki eşit olmayan nesnenin aynı hash kodunu kullanmasına izin verilir. Bu yalnızca bir çakışmadır ve harita bunu equals() ile ele alır.

Dolayısıyla yasak olan tek durum, farklı hash kodlarına sahip eşit nesnelerdir.

public class Main {
    public static void main(String[] args) {
        // Equal value, unequal objects, same hash is fine
        System.out.println("FB".hashCode() == "Ea".hashCode());
        System.out.println("FB".equals("Ea"));
    }
}

Yalnızca equals'ı Yeniden Tanımlayan Bir Sınıf

İşte hatalı bir sınıf. equals() yöntemini yeniden tanımlıyor, ancak hashCode() yöntemini yeniden tanımlamıyor.

Artık mantıksal olarak eşit olan iki noktanın, temel nesne sınıfından devralınan farklı hash kodları vardır ve bu durum sözleşmeyi ihlal eder.

public class Main {
    static class Point {
        final int x, y;
        Point(int x, int y) { this.x = x; this.y = y; }
        @Override public boolean equals(Object o) {
            if (!(o instanceof Point p)) return false;
            return x == p.x && y == p.y;
        }
        // BUG: no hashCode override
    }
    public static void main(String[] args) {
        Point a = new Point(1, 2);
        Point b = new Point(1, 2);
        System.out.println("equals: " + a.equals(b));
        System.out.println("same hash: " + (a.hashCode() == b.hashCode()));
    }
}

HashSet'teki Hata

Hatalı sınıf bir HashSet içinde başarısız olur. Küme, yanlış hash'in seçtiği kovaya bakar ve eşit öğeyi hiçbir zaman bulamaz.

Sonuçta, reddedilmeleri gerekirken yinelenen öğeler elde edersiniz.

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

public class Main {
    static class Point {
        final int x, y;
        Point(int x, int y) { this.x = x; this.y = y; }
        @Override public boolean equals(Object o) {
            if (!(o instanceof Point p)) return false;
            return x == p.x && y == p.y;
        }
    }
    public static void main(String[] args) {
        Set<Point> set = new HashSet<>();
        set.add(new Point(1, 2));
        set.add(new Point(1, 2));
        System.out.println("size = " + set.size());
    }
}

Düzeltme

Her iki yöntemi de yeniden tanımlayın ve bunları aynı alanlardan türetin. Böylece eşit nesneler aynı hash'i paylaşır ve aynı kovaya düşer.

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

public class Main {
    static class Point {
        final int x, y;
        Point(int x, int y) { this.x = x; this.y = y; }
        @Override public boolean equals(Object o) {
            if (!(o instanceof Point p)) return false;
            return x == p.x && y == p.y;
        }
        @Override public int hashCode() { return Objects.hash(x, y); }
    }
    public static void main(String[] args) {
        Set<Point> set = new HashSet<>();
        set.add(new Point(1, 2));
        set.add(new Point(1, 2));
        System.out.println("size = " + set.size());
    }
}

equals Yansımalı Olmalıdır

Doğru bir equals() dört özelliğe uyar. İlki yansımalı olmasıdır: x.equals(x) doğru olmalıdır.

Bu açıkça anlaşılır görünür, ancak aynı başvuru durumunu ele almayı unutursanız özel mantık bunu bozabilir.

public class Main {
    public static void main(String[] args) {
        String x = "java";
        System.out.println(x.equals(x));
    }
}

Simetrik ve Geçişli

İki kural daha vardır:

  • Simetrik: a.equals(b) ise b.equals(a) da olmalıdır.
  • Geçişli: a.equals(b) ve b.equals(c) ise a.equals(c) de olmalıdır.

Bir sınıf hiyerarşisinde türleri karıştırmak çoğu zaman simetriyi bozar; bu nedenle sınıfları dikkatle karşılaştırın.

public class Main {
    public static void main(String[] args) {
        String a = "x", b = "x", c = "x";
        boolean symmetric = a.equals(b) == b.equals(a);
        boolean transitive = a.equals(b) && b.equals(c) && a.equals(c);
        System.out.println("symmetric: " + symmetric);
        System.out.println("transitive: " + transitive);
    }
}

Tutarlı

Dördüncü kural tutarlı olmaktır: nesneler değişmediği sürece, tekrarlanan çağrılar aynı sonucu döndürür.

Bu nedenle equals ve hashCode yöntemlerini değişmez alanlara dayandırmalısınız. Ekledikten sonra hashCode'da kullanılan bir alanı değiştirmek haritanın yapısını bozar.

import java.util.Objects;

public class Main {
    public static void main(String[] args) {
        // Immutable record gives consistent equals/hashCode automatically
        record Id(int value) {}
        Id id = new Id(7);
        System.out.println(Objects.equals(id, new Id(7)));
        System.out.println(id.hashCode() == new Id(7).hashCode());
    }
}

Kayıtlar Bunu Sizin İçin Yapar

Bir Java record, tüm bileşenlerinden otomatik olarak equals() ve hashCode() üretir.

Değer benzeri veriler için kayıtları tercih edin. Sözleşme ek bir çaba gerektirmeden karşılanır ve yöntemler eşzamanlı kalır.

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

public class Main {
    record Point(int x, int y) {}
    public static void main(String[] args) {
        Set<Point> set = new HashSet<>();
        set.add(new Point(1, 2));
        set.add(new Point(1, 2));
        System.out.println("size = " + set.size());
    }
}

Değiştirilebilir Anahtar Tuzağı

Bir nesneyi haritaya koyduktan sonra hashCode'da kullanılan bir alanı değiştirirseniz, artık onu bulamazsınız.

Harita eski kovaya bakar; nesne artık yeni bir hash değerine sahip olur. Girdi, kayıp bir hayalete dönüşür.

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public class Main {
    static class Box {
        int id;
        Box(int id) { this.id = id; }
        @Override public boolean equals(Object o) {
            return o instanceof Box b && b.id == id;
        }
        @Override public int hashCode() { return Objects.hash(id); }
    }
    public static void main(String[] args) {
        Map<Box, String> m = new HashMap<>();
        Box key = new Box(1);
        m.put(key, "value");
        key.id = 99; // mutated after insertion
        System.out.println(m.get(key));
    }
}

Hızlı Kontrol

Sözleşmeyi ne kadar kavradığınızı test edin.

Özet

equals/hashCode sözleşmesini öğrendiniz:

  • Eşit nesnelerin hash kodları eşit olmalıdır.
  • equals yansımalı, simetrik, geçişli ve tutarlı olmalıdır.
  • Her iki yöntemi de aynı değişmez alanlara dayandırın.
  • Kayıtlar doğru uygulamaları ek bir çaba gerektirmeden üretir.

Sırada, kendi doğru hashCode yönteminizi elle yazacaksınız.

import java.util.Objects;

public class Main {
    public static void main(String[] args) {
        System.out.println("Contract recap: " + Objects.hash(1, 2, 3));
    }
}

Sıkça Sorulan Sorular

“equals/hashCode Sözleşmesi” dersi ücretsiz mi?

Evet — “equals/hashCode Sözleşmesi” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve Java Academy kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. Java Academy kursu toplamda 4 dersten oluşur.

“equals/hashCode Sözleşmesi” dersinde ne öğreneceğim?

İkisinin neden uyumlu olması gerektiği Java Academy ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.

Java Academy öğrenmeye başlamak için deneyim gerekli mi?

Önceden deneyim gerekmez. CoddyKit'te Java Academy, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 2. dersidir.

“equals/hashCode Sözleşmesi” dersi ne kadar sürer?

Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.

Bu Java Academy dersinde kod yazıp çalıştırabilir miyim?

Evet. Her Java Academy dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.

Bu kursun tüm dersleri

  1. HashMap Nasıl Çalışır
  2. equals/hashCode Sözleşmesi
  3. hashCode Uygulama
  4. Ağaçlaştırma ve Performans
← Java Academy Sayfasına Dön