Interviewantworten II – die erste Antwort

Die Frage war, warum Object.hashCode() und Object.equals(Object) immer beide überschrieben werden sollten.

Die Antwort findet sich direkt in der Javadoc-Dokumentation von Object.hashCode():

If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

Vereinfacht gesagt: Überschreibt man nur equals() und es werden zwei unterschiedliche Instanzen einer Klasse verglichen, die laut equals() aber gleich sind, so bricht man den Kontrakt von Object.hashCode(). Die beiden HashCodes wären unterschiedlich, obwohl die Objekte nach equals() gleich sind.

Um das Ganze ein wenig praktischer zu beschreiben, nehmen wir folgende Klasse an:

public class Person {
  private String firstName;
  private String lastName;
  private Date dateOfBirth;
  private String favoriteBeer;

  // ...getter/setter

  // wir nehmen an, zwei Personen sind identisch, wenn sie gleich heißen und am gleichen Tag geboren wurden

  // bitte IMMER @Override nutzen, wenn Java >= 1.5 verwendet wird!
  @Override
  public boolean equals(Object o) {
    Person otherPerson = (Person) o;
    return
      firstName.equals(o.getFirstName()) &&
      lastName.equals(o.getLastName()) &&
      dateOfBirth.equals(o.getDateOfBirth());
  }
}

In obigem Beispiel wurde nur equals überschrieben und dieser Vergleich macht durchaus Sinn. Aber was passiert, wenn wir zwei Personen gleichen Namens und mit gleichem Geburtsdatum in ein HashSet einfügen wollen? Da das HashSet – wie der Name schon sagt – den HashCode eines Objekts als Vergleichsfunktion heranzieht um zu bestimmen, ob dieses Objekt schon einmal im Set vorhanden ist, würden problemlos beide Objekte im Set abgelegt werden. Und das, obwohl sie doch equals() sind! Hier hilft natürlich, eine .hashCode()-Methode zu schreiben, die genau die gleichen Felder berücksichtigt wie .equals().

Das Erstellen von hashCode und equals ist übrigens mit IDEs einfach gemacht. Unter Eclipse kann man über Source -> generate hashCode() and equals() komfortabel auswählen, welche Felder in die Methoden einbezogen werden sollen. Andere IDEs bieten vermutlich ähnliche Funktionen. Programmatisch kann man über den EqualsBuilder respektive den HashCodeBuilder aus den Apache Commons diese Sachen einfach erledigen.

Leave a Reply