equals() and hashCode()

exercise No. 242

Q:

Consider the following Person class:

public class Person {

    private String name, comment; // Guaranteed never to be null

    private  int ageInYears;

    // Other methods omitted for brevity
      ...
    @Override public boolean equals(Object o) {
        if (o instanceof  Person p) {
            return ageInYears == p.ageInYears && name.equals(p.name);
        } else {
            return false;
        }
    }

    @Override public int hashCode() {
        return ageInYears + 13 * comment.hashCode();
    }
}

Answer the following two questions:

  1. Is this implementation sound regarding the contract between equals() and hashCode()? Correct if necessary.

  2. After correcting possible flaws: Is the resulting implementation »good« with respect to distinguishing objects? Amend if possible.

Explain your answers.

A:

  1. The equals(...) method defines two Person instances to be equal when having common age and Name. Thus two instances e.g. (18, "Eve Porter", "New Friend from holiday") and (18, "Eve Porter", "Friendly person") of common name and age but different comment will still considered equal.

    Since equality is being defined solely on age and name the comment attribute must not be used for implementing hashCode(). Otherwise the above example will result in different hash values contradicting the equals(...) / hashCode() contract. We thus have:

    public class Person {
      ...
        @Override public int hashCode() {
            return ageInYears;
        }
    }
  2. The previously corrected hashCode() implementation is correct with respect to its related equals() method. However the equals(...) method defines all Person instances of common age but different name are to be different. These will however share the same hashCode() value throughout. Our hashCode() method is thus not well suited when it comes to distinguishing objects. Adding the name property's hash code improves the implementation:

    public class Person {
      ...
        @Override public int hashCode() {
            return ageInYears + 13 * name.hashCode();
        }
    }