تعتمد طريقة hashCode() عندما يساوي() على حقول مستقلة متعددة

StackOverflow https://stackoverflow.com/questions/479105

  •  20-08-2019
  •  | 
  •  

سؤال

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

public class MyClass {
  int id;
  String name;

  public boolean equals(Object o) {
    if (!(o instanceof MyClass))
      return false;
    MyClass other = (MyClass) o;
    if (other.id == this.id || other.name == this.name)
      return true;
    return false;
  }
}

كيف أكتب دالة hashCode() لهذه الفئة؟وأريد تجنب الحالة التافهة هنا المتمثلة في إرجاع ثابت مثل:

public int hashCode() {
  return 1;
}
هل كانت مفيدة؟

المحلول

لا أعتقد أن رمز التجزئة غير البديهي موجود.أيضا لديك equals() ينتهك العقد العام كما جاء في API --- إنها ليست متعدية:

(1,2) يساوي (1,3)

(4,3) يساوي (1,3)

لكن (4,3) يكون غير متساوي ل (1,2).


ومن باب الإكتمال أقدم لكم السكيت-نيكو برهان =)

مطالبة: يجب أن يكون رمز التجزئة هو الوظيفة الثابتة التافهة.

دليل:يترك (a,b) و (c,d) أن يكونا كائنين لهما رموز تجزئة مميزة، على سبيل المثال. h(a,b) ≠ h(c,d).النظر في الكائن (a,d).حسب تعريف OP، (a,d) مساوي ل (a,b), ، و (a,d) مساوي ل (c,d).ويترتب على ذلك عقد رمز التجزئة الذي - التي h(a,d) = h(a,b) = h(c,d);تناقض.

نصائح أخرى

وطيب، في السيناريو الخاص بك، وتجاهل متطلبات API لثانية واحدة، لا يوجد وظيفة تجزئة غير ثابتة

وتخيل كان هناك hashfunction التي لديها قيم مختلفة ل

و(أ، ب)، (أ، ج)، ب! = ج، ثم تجزئة (أ، ب)! = تجزئة (أ، ج)، إفنثوو (أ، ب) = (أ، ج).

وعلى نحو مماثل، (ب، أ) و (ج، أ) يجب أن تنبعث من نفس شفرة التجزئة.

ودعونا ندعو لدينا التجزئة وظيفة ساعة. نجد:

ح (س، ص) = ح (س، ث) = ح (ت، ث) فورال س، ص، ت، ث.

وبالتالي، فإن hashFunction فقط أن تفعل ما تريده هو ثابت.

وأنا متأكد من حق زاك - ليس هناك شفرة التجزئة غير تافهة للقيام بذلك

والزائفة البرهان:

والنظر في أي اثنين غير متساوية القيم، X = (ID1، NAME1) وY = (ID2، NAME2).

وتنظر الآن Z = (ID2، NAME1). هذا يساوي كل من X و Y، لذلك يجب أن يكون نفس شفرة التجزئة على حد سواء X و Y. لذا X و Y يجب أن يكون نفس شفرة التجزئة - وهو ما يعني <م> جميع القيم يجب أن يكون نفس شفرة التجزئة

وهناك سبب لماذا كنت قد وصلت الى حالة غريبة - كنت كسر طبيعة متعدية على قدم المساواة. حقيقة أن X.equals (Z) وZ.equals (Y) <م> يجب يعني أن X.equals (Y) - ولكن لم يحدث ذلك. تعريفك المساواة ليست مناسبة للحصول على العقد العادي على قدم المساواة.

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

وTransitivity يعني لمدة ثلاث س غير فارغة، ص، ض، إذا x.equals(y)، y.equals(z)، ثم x.equals(z). في المثال الخاص بك، كائن x={id: 1, name: "ha"}، y={id: 1, name: "foo"}، z={id: 2, name: "bar"} يكون هذا (x.equals(y) and y.equals(z)) الممتلكات. ومع ذلك، x.equals(z) هو false. يجب أن يكون كل وسيلة equals() هذه الخاصية، راجع مستندات API جافا.

عودة إلى وظائف تجزئة: كل وظيفة يخلص بنا إلى التكافؤ التي حددتها f(x)==f(y). وهذا يعني إذا كنت مهتما في المقارنة بين القيم وظيفة وتريد أن يعود صحيحا إذا x==y (وربما في حالات أخرى)، سوف تتلقى علاقة متعدية، وهو ما يعني عليك أن تنظر ما لا يقل عن إغلاق متعدية من الكائنات التكافؤ. في الحالة الخاصة بك، وإغلاق متعدية هي العلاقة تافهة (كل شيء يساوي أي شيء). مما يعني أنك لا يمكن تمييز الأشياء المختلفة عن طريق أي وظيفة.

هل تعرف عمدا المساواة كما هو الحال عندما هويات متساوية أو أسماء متساوون .. سوفت ل"OR" يكون "AND"؟

إذا كنت تعني "AND" ثم ينبغي أن تحسب شفرة التجزئة باستخدام نفس جدا أو أقل (ولكن أبدا استخدام حقول غير المستخدمة من قبل الأنداد) حقول كنت من قبل الأنداد ().

إذا كنت تعني "OR" فإنك ص يجب أن لا تتضمن hashgcode هوية أو اسم في حساب شفرة التجزئة والتي يتم لا حقا معنى.

وتحرير: أنا لم أقرأ السؤال بعناية

.

-

وسوف تستخدم العموم لانغ جرة.

وXOR على شفرة التجزئة أعضاء ينبغي ان يعمل. كما ينبغي أن تنفذ شفرة التجزئة () ويساوي () بشكل صحيح.

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

public hashCode(){
   return new AssertionError();
}

أو

 public class MyClass {
   final int id;
   final String name;
   // constructor
 }

أو

public class MyClass {
   private int id;
   private String name;
   boolean hashed=false;
   public void setId(int value){
     if(hashed)throw new IllegalStateException();
     this.id=value;
   }
   public void setName(String value){
     if(hashed)throw new IllegalStateException();
     this.name=value;
   }
   // your equals() here
   public hashCode(){
     hashed=true;
     return new HashCodeBuilder().append(id).append(name).toHashCode();
   }
}

وبعد إعادة قراءة السؤال.

ويمكنك صناعة السيارات في إكمال حقل آخر عند واحد منهم يتم تحديثه.

-

وتحرير: رمزي قد يقول أفضل ثم لغتي الإنجليزية

.
void setName(String value){
  this.id=Lookup.IDbyName(value);
}
void setID(String value){
  this.name=Lookup.NamebyId(value);
}

وتحرير 2:

وكود بشأن مسألة قد خاطئ كما سيعود دائما صحيحا إلا إذا قمت بتعيين كل من معرف واسم.

إذا كنت تريد حقا الطريقة التي تفعل متساوين جزئية، إنشاء كنت تملك API التي تسمى "partialEquals ()".

وأبسط الطريق هو XOR لhashcodes كل حقل على حدة. هذا وقد القبح طفيفة في بعض الحالات (على سبيل المثال في X، Y تنسق، فإنه يتسبب في حالة تنطوي على الفقراء وجود علامات الرقم متساوية عند الوجه X و Y)، ولكن هو عموما فعال جدا. قرص حسب الحاجة للحد من حوادث الاصطدام إذا لزم الأمر لتحقيق الكفاءة.

وماذا عن هذا

public override int GetHashCode()
{
    return (id.ToString() + name.ToString()).GetHashCode();
}

وظيفة يجب أن لل Allways عودة تجزئة "صالح" ...

وتحرير: لاحظت فقط التي تستخدمها "أو" لا "و": P بالاضافة الى انني اشك في ان يكون هناك أي حل جيد لهذه المشكلة ...

وماذا عن

public override int GetHashCode()
{
    return id.GetHashCode() ^ name.GetHashCode();
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top