hashCode() method when equals() is based on multiple independent fields

前端 未结 10 2145
执念已碎
执念已碎 2021-02-08 09:16

i have a class whose equality is based on 2 fields such that if either one is equal then the objects of this type are considered equal. how can i write a hashCode() function for

相关标签:
10条回答
  • 2021-02-08 09:21

    Have you intentionally defined equality as when ids are equal OR names are equal.. Shouldnt the "OR" be a "AND" ?

    If you meant "AND" then your hashcode should be calculated using the very same or less (but never use fields not used by equals) fields you are by equals().

    If you meant "OR" then you r hashgcode should not include id or name in its hashcode calculation which doesnt really make sense.

    0 讨论(0)
  • 2021-02-08 09:25

    I don't think a nontrivial hashcode exists. Also, your equals() violates the general contract as stated in the API --- it is not transitive:

    (1,2) equals (1,3)

    (4,3) equals (1,3)

    But (4,3) is not equal to (1,2).


    For the sake of completeness, I present to you the Skeet-Niko proof =)

    Claim: The hashcode must be the trivial constant function.

    Proof: Let (a,b) and (c,d) be two objects with distinct hashcodes, i.e. h(a,b) ≠ h(c,d). Consider the object (a,d). By the OP's definition, (a,d) is equal to (a,b), and (a,d) is equal to (c,d). It follows from the hashcode contract that h(a,d) = h(a,b) = h(c,d); a contradiction.

    0 讨论(0)
  • 2021-02-08 09:29

    EDIT: I didn't read the question carefully.

    --

    I'll use commons-lang jar.

    XOR the members hashCode should works. As they should implements hashCode() and equals() correctly.

    However, your code may wrong if you don't protect your hashCode. Once it was hashed, it should not be changed. It should be prevented from being happen.

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

    or

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

    or

    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();
       }
    }
    
    0 讨论(0)
  • 2021-02-08 09:32

    Ok, in your scenario, ignoring the API requirements for a second, there is no non-constant hash function

    Imagine there were a hashfunction which has different values for

    (a,b), (a,c), b!=c, then hash(a,b) != hash(a,c), eventhough (a,b) = (a,c).

    Similarly, (b,a) and (c,a) must emit the same hashCode.

    Let's call our hash-function h. We find:

    h(x,y) = h(x,w) = h(v,w) forall x,y,v,w.

    Hence, the only hashFunction that does what you want is constant.

    0 讨论(0)
  • 2021-02-08 09:33

    How about this

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

    The function should allways return a "valid" hash...

    Edit: just noticed that you use "or" not "and" :P well i doubt there is any good solution to this problem...

    0 讨论(0)
  • 2021-02-08 09:40

    After re-read the question.

    You may auto-complete the another field when one of them being updated.

    --

    EDIT: My code may say better then my English.

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

    EDIT 2:

    The code on the question may wrong as will always return true unless you've set both the id & name.

    If you really want a method that do partial equals, create you own API that named "partialEquals()".

    0 讨论(0)
提交回复
热议问题