عندما تستبدل equals() لتعريف المساواة المنطقية، يجب عليك أيضاً استبدال hashCode() — لأن المجموعات المعتمدة على hash (HashMap, ) تعتمد على العقد بأن . كسر هذا العقد يؤدي إلى أخطاء دقيقة يصعب إيجادها.
HashSet// by default, equals() compares IDENTITY (same object?), hashCode() is based on memory address
Person p1 = new Person("Ann", 30);
Person p2 = new Person("Ann", 30);
p1.equals(p2); // false by default — different objects, even with same data
بدون استبدال، كائنان بنفس المحتوى لا يعتبران "متساويين" — عادةً ليس ما تريده لكائنات القيمة.
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person p = (Person) o;
return age == p.age && Objects.equals(name, p.name); // compare by CONTENT
}
@Override
public int hashCode() {
return Objects.hash(name, age); // MUST be consistent with equals()
}
العقد: إذا كان a.equals(b) صحيحاً، فيجب أن يكون a.hashCode() == b.hashCode() صحيحاً أيضاً.
Person p1 = new Person("Ann", 30);
Person p2 = new Person("Ann", 30); // equal by our equals()
Set<Person> set = new HashSet<>();
set.add(p1);
set.contains(p2); // ❌ likely FALSE — even though p1.equals(p2)!
لماذا؟ HashMap/HashSet أولاً يستخدم hashCode() للعثور على الدلو الصحيح، ثم equals() داخله. مع الافتراضي (القائم على الهوية) hashCode()، p1 و p2 ينتهي بهما الحال في دلاء مختلفة، لذا contains لا يقارنهما أبداً — المجموعة تظن أنهما مختلفان. هذا ينتج أخطاء محيّرة: نسخ مكررة في Set، فشل البحث في map، إلخ.
1. equal objects → equal hash codes (REQUIRED for correctness)
2. unequal objects MAY have the same hash (collisions are allowed)
3. hashCode() must be consistent (same object → same code, unchanged)
4. equals() must be reflexive, symmetric, transitive, consistent
record Person(String name, int age) {} // records auto-generate equals/hashCode/toString!
Java records (وتوليد IDE / Lombok) ينتج equals/hashCode صحيح ومتسق لك.
عقد equals/hashCode هو واحد من أهم القواعس في Java — وأكثرها انتهاكاً — قواعد.
استبدال equals() بدون hashCode() يكسر المجموعات المعتمدة على hash بطرق يصعب تصحيحها: الكائنات التي تعتبرها متساوية تُفقد في HashMap/HashSet (فشل البحث، نسخ مكررة وهمية) لأنها تُهضم إلى دلاء مختلفة.
بما أن هذه المجموعات منتشرة في كل مكان، يجب على كل فئة نوع القيمة المستخدمة كمفتاح أو عنصر مجموعة أن تستبدل كليهما بشكل متسق.
فهم السبب (آلية البحث دلو-ثم-المساواة) — واستخدام records أو الكود المُنتج لالتزام به بشكل صحيح — ضروري للسلوك الصحيح وهو موضوع مقابلة كلاسيكي يكشف الفهم الحقيقي لكيفية عمل مجموعات Java.