سؤال

في جافا، لدي فئة فرعية Vertex من فئة Java3D Point3f.الآن Point3f يحسب equals() بناء على قيم إحداثياتها، ولكن بالنسبة لي Vertex فئة أريد أن أكون أكثر صرامة:الرأسان متساويان فقط إذا كانا نفس الجسم.حتى الان جيدة جدا:

class Vertex extends Point3f {

    // ...

    public boolean equals(Object other) {
        return this == other;
    }
}

أعلم أن هذا ينتهك عقد equals(), ، لكن بما أنني سأقارن الرؤوس بالرؤوس الأخرى فقط، فهذه ليست مشكلة.

الآن، لتكون قادرة على وضع القمم في HashMap, ، ال hashCode() يجب أن ترجع الطريقة نتائج متوافقة مع equals().وهو يفعل ذلك حاليًا، ولكن من المحتمل أن يبني قيمة الإرجاع الخاصة به على حقول Point3f, ، وبالتالي سيعطي تصادمات تجزئة مختلفة Vertex كائنات لها نفس الإحداثيات.

ولذلك أود أن قاعدة hashCode() على عنوان الكائن، بدلاً من حسابه من Vertexحقول.أعلم أن Object الفصل يفعل هذا، ولكن لا أستطيع أن أسميه hashCode() طريقة لأن Point3f يتجاوز ذلك.

لذا، في الواقع سؤالي ذو شقين:

  • وينبغي لي حتى أريد مثل هذه الضحلة equals()?
  • إذا كانت الإجابة بنعم، فكيف يمكنني الحصول على عنوان الكائن لحساب رمز التجزئة منه؟

يحرر:خطر على بالي شيء...يمكنني إنشاء عشوائي int القيمة عند إنشاء الكائن، واستخدامها لرمز التجزئة.هل هذه فكرة جيدة؟ولم لا)؟

هل كانت مفيدة؟

المحلول

إما أن تستخدم System.identityHashCode() أو تستخدم IdentityHashMap.

نصائح أخرى

System.identityHashCode() تقوم بإرجاع نفس رمز التجزئة للكائن المحدد كما سيتم إرجاعه بواسطة الطريقة الافتراضية hashCode(), ، سواء تم تجاوز فئة الكائن المحدد أم لا hashCode().

يمكنك استخدام مندوب على الرغم من هذا إجابة ربما يكون أفضل.


class Vertex extends Point3f{
   private final Object equalsDelegate = new Object();
   public boolean equals(Object vertex){
      if(vertex instanceof Vertex){
         return this.equalsDelegate.equals(((Vertex)vertex).equalsDelegate);
      }
      else{
         return super.equals(vertex);
      }
   }
   public int hashCode(){
      return this.equalsDelegate.hashCode();
   }
}

لمعلوماتك فقط، طريقة التساوي الخاصة بك لا تنتهك عقد التساوي (بالنسبة لعقد الكائن الأساسي)...هذه هي في الأساس طريقة يساوي لأسلوب الكائن الأساسي، لذلك إذا كنت تريد تساوي الهوية بدلاً من تساوي Vertex، فلا بأس بذلك.

أما بالنسبة لرمز التجزئة، فأنت لا تحتاج حقًا إلى تغييره، على الرغم من أن الإجابة المقبولة تعد خيارًا جيدًا وستكون أكثر كفاءة إذا كان جدول التجزئة الخاص بك يحتوي على الكثير من المفاتيح الرأسية التي لها نفس القيم.

السبب وراء عدم حاجتك إلى تغييره هو أنه من الجيد تمامًا أن يُرجع رمز التجزئة نفس القيمة للكائنات التي تساوي إرجاع خطأ ...بل إنه رمز تجزئة صالح لإرجاع 0 طوال الوقت لكل مثيل.ما إذا كان هذا فعالاً بالنسبة لجداول التجزئة هي مسألة مختلفة تمامًا ...سوف تحصل على الكثير من التصادمات إذا كان الكثير من الكائنات الخاصة بك لها نفس رمز التجزئة (والذي قد يكون هو الحال إذا تركت رمز التجزئة بمفرده وكان لديك الكثير من القمم بنفس القيم).

من فضلك لا تقبل هذا كإجابة رغم ذلك بالطبع (ما اخترته هو أكثر عملية)، أردت فقط أن أقدم لك المزيد من المعلومات الأساسية حول رموز التجزئة ويساويها؛-)

لماذا تريد تجاوز hashCode() في المقام الأول؟قد ترغب في القيام بذلك إذا كنت تريد العمل مع تعريف آخر للمساواة.على سبيل المثال

الفئة العامة A {int id ؛

منطقية عامة تساوي (a other) {return other.id == id} public int hashcode () {return id ؛}

} حيث تريد أن تكون واضحًا أنه إذا كان المعرف هو نفسه ، فإن الكائنات هي نفسها ، وتجاوز رمز hashcode بحيث لا يمكنك القيام بذلك:

HashSet hash= new HashSet();hash.add(new A(1));hash.add(new A(1));واحصل على 2 متطابقين (من وجهة نظر تعريفك للمساواة) A's.سيكون السلوك الصحيح هو أنه سيكون لديك كائن واحد فقط في التجزئة، وسيتم استبدال الكتابة الثانية.

نظرًا لأنك لا تستخدم المساواة كمقارنة منطقية، بل مقارنة مادية (أي.إنه نفس الكائن)، الطريقة الوحيدة التي ستضمن بها أن رمز التجزئة سيرجع قيمة فريدة، هي تنفيذ شكل مختلف من اقتراحك.بدلاً من إنشاء رقم عشوائي، استخدم UUID لإنشاء قيمة فريدة فعلية لكل كائن.

سيعمل System.identityHashCode()، معظم في ذلك الوقت، ولكن ليس مضمونًا مثل طريقة Object.hashCode() لا مضمون لإرجاع قيمة فريدة لكل كائن.لقد رأيت الحالة الهامشية تحدث، ومن المحتمل أن تعتمد على تطبيق VM، وهو ليس شيئًا تريد أن يعتمد عليه الكود الخاص بك.

مقتطف من javadocs لـ Object.hashCode():بقدر ما هو عملي إلى حد معقول، فإن طريقة hashCode المحددة بواسطة فئة Object تقوم بإرجاع أعداد صحيحة مميزة لكائنات مميزة.(يتم تنفيذ ذلك عادةً عن طريق تحويل العنوان الداخلي للكائن إلى عدد صحيح، ولكن تقنية التنفيذ هذه غير مطلوبة بواسطة لغة برمجة JavaTM.)

المشكلة التي يعالجها هذا هي حالة وجود كائنين نقطيين منفصلين يمنعان من الكتابة فوق بعضهما البعض عند إدراجهما في خريطة التجزئة لأن كلاهما لهما نفس التجزئة.نظرًا لعدم وجود مساواة منطقية، مع التجاوز المصاحب لـ hashCode()، يمكن أن تتسبب طريقة الهويةHashCode في حدوث هذا السيناريو بالفعل.عندما تستبدل الحالة المنطقية فقط إدخالات التجزئة لنفس النقطة المنطقية، فإن استخدام التجزئة المستندة إلى النظام يمكن أن يتسبب في حدوثها مع أي كائنين، ولم تعد المساواة (وحتى الفئة) عاملاً.

الدالة hashCode() موروثة من الكائن وتعمل تمامًا كما تريد (على مستوى الكائن، وليس على مستوى الإحداثيات).لا ينبغي أن تكون هناك حاجة لتغييره.

أما بالنسبة لطريقة التساوي، فلا يوجد سبب لاستخدامها، حيث يمكنك فقط إجراء obj1 == obj2 في التعليمات البرمجية الخاصة بك بدلاً من استخدام التساوي، نظرًا لأنها مخصصة للفرز وما شابه، حيث تكون مقارنة الإحداثيات أكثر منطقية.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top