简体   繁体   中英

how to override this hashCode method?

as for the definition of Person:

public class Person {
    private int id;
    private int characteristics;
    public boolean equals (Object obj) {
           if (obj == this) {
                 return true;
           }
           if (obj instanceof Person) {
                 if (id == ((Person) obj).id) {
                     return true;
                 } else if (characteristics == ((Person) obj).characteristics) {
                     return true;
                 }
           }
           return false;
    }
}

cause 2 Person objects a and b must have the identical hash code if a.equals(b) returns true , how should I implement the hashCode method?

solution

my equals method implementation is incorrect according to Java's equivalence protocol: transitivity is not satisfied: a.id = 1 , a.characteristic = 2 , b.id = 1 , b.characteristic = 3 , c.id = 2 , c.characteristic = 3 ; a.equals(b) == true , b.equals(c) == true , but a.equals(c) == false .

Since your class considers objects equal when either of their respective id or characteristics fields are equal, the only hash code you can reasonably use here is a constant value for all instances:

public int hashCode() {
    return 0;
}

This will make hash-based lookups perform horribly.

An either-or test in equals() is generally a bad idea; the objects aren't actually equal , are they? Maybe they are just a "match for each other?" Perhaps you should consider leaving equals() alone and implementing some other comparison method.


As Thomasz pointed out, your equals() test is not transitive; if a.equals(b) && b.equals(c) is true then a.equals(c) must be true. This is not true with your overload, and therefore your implementation breaks the contract of equals() . I would strongly urge you to implement this test in a different method and leave equals() alone.

This is what auto-generated for your class:

@Override
public int hashCode() {
    int result = id;
    result = 31 * result + characteristics;
    return result;
}

And after few refactorings:

@Override
public int hashCode() {
    return 31 * id + characteristics;
}

And for the record, is it just me or is your equals() broken? You consider two objects equal if either id s or characteristics are equal, but not necessarily both of them. This means your equality is not transitive which might have really unexpected side effects once your object goes into wilderness.

Here is a decent implementation:

@Override
public boolean equals(Object o) {
    if (this == o) {
        return true;
    }
    if (!(o instanceof Person)) {
        return false;
    }

    Person person = (Person) o;
    return characteristics == person.characteristics && id == person.id;
}

If having the same id implies always having the same characteristics (which seems necessary for your equals() to be valid), then your hash code can use characteristics alone:

@Override
public int hashCode() {
    return characteristics;
}

If that's not the case, you may want to reconsider using Java equality to express this relation, as @cdhowie suggests.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM