equals()/hashCode() tief oder flach und mehrdimensionale Arrays
0 Kommentar(e). Veröffentlicht von Christian Ullenboom am Montag, November 02, 2009.Tiefe oder flache Vergleiche/Hash-Werte
Referenziert ein Objekt Unterobjekte (etwa eine Person ein String-Objekt für den Namen – keine Primitiven – so geben die Methoden equals() und hashCode()den Vergleich bzw. Berechung des Hashcodes an das referenzierte Unterobjekt weiter (wenn es denn nicht-null ist). Ablesen können wir das an folgendem Ausschnitt unserer equals()-Methode.
com/tutego/insel/object/hashcode/Player.java, equals() Ausschnitt
if ( name == null )
if ( ((Player)that).name != null )
return false;
else if ( !name.equals( ((Player)that).name ) )
return false;
if ( ((Player)that).name != null )
return false;
else if ( !name.equals( ((Player)that).name ) )
return false;
Es ist demnach Aufgabe der String-Klasse (name ist vom Typ String) den Gleichheitstest vorzunehmen. Das heißt, dass zwei Personen problemlos equals()-gleich sein können, auch wenn sie zwei nicht-identische, aber equals()-gleiche String-Objekte referenzieren.
Auch bei hashCode() ist diese Delegation an das referenzierte Unterobjekt abzulesen:
com/tutego/insel/object/hashcode/Player.java, hashCode() Ausschnitt
result = 31 * result + ((name == null) ? 0 : name.hashCode());
Dass eine equals()-Methode bzw. hashCode() einer Klasse den Vergleich bzw. die Hashcode-Berechnung nicht an die Unterobjekte delegiert, sondern selbst umsetzt, ist unüblich.
equals()/hashCode()-Berechnung bei (mehrdimensionalen) Arrays
Einen gewissen Sonderfall bei equals()/hashCode() nehmen mehrdimensionale Arrays ein. Mehrdimensionale Arrays sind nichts anderes als Arrays von Arrays. Das erste Array für die erste Dimension referenziert jeweils auf Unterarrays für die zweite Dimension. Wichtig wird diese Realisierung bei der Frage, wie diese Verweise der ersten Dimension nun bei equals() betrachtet werden sollen. Denn hier stellt sich die Frage, ob die Unterarrays von zwei zu testenden Arrays nur identisch oder auch gleich sein dürfen. Diese Frage hatten wir schon im Kapitel 3, „Felder vergleichen mit Arrays.equals() und Arrays.deepEquals()“ angesprochen.
Enthält unsere Klasse ein Array und es soll in einem equals() mit berücksichtigt werden, so sind prinzipiell drei Varianten zum Umgang mit diesem Array möglich. Felder selbst einfach mit == wie primitive Werte zu vergleichen ist keine gute Lösung, da Arrays Objekte sind, die wie Strings nicht einfach mit == zu vergleichen sind. Während allerdings Objekte ein equals() haben, bieten Arrays keine eigene equals()-Methode, sondern diese ist in die Utility-Klasse Arrays gewandert. Hier gibt es jedoch 2 Methoden die die in Frage kämen. Arrays.equals(Object[] a, Object[] a2) geht jedes Element von a, also bei mehrdimensionalen Arrays jede Referenz auf ein Unterarray durch, und testet, ob es identisch zu einem zweiten Feld a2 ist. Wenn also zwei gleiche aber nicht-identische Hauptarrays identische Unterarray besitzen, liefert Arrays.equals() die Rückgabe true, aber nicht, wenn die Unterarrays zwar gleich, aber nicht identisch sind. Spielt das eine Rolle, so ist Arrays.deepEquals() die passende Methode, denn sie geht fragt immer mit equals() die Unterarray ab.
Bei der Berechnung vom Hash-Wert gibt es eine vergleichbare Frage. Die Arrays-Klasse bietet zur Berechnung vom Hash-Wert eines ganzes Arrays die Methoden Arrays.hashCode() und Arrays.deepHashCode(). Die erste Methode fragt jedes Unterelement über die von Object angebotene Methode hashCode() nach dem Hash-Wert. Nehmen wir ein mehrdimensionales Array an. Dann ist das Unterelement ebenfalls ein Feld. Arrays.hashCode() wird dann wie erwähnt nur die hashCode()-Methode auf dem Feld-Objekt aufrufen, während Arrays.deepHashCode() auch Unterarray herabsteigt und solange Arrays.deepHashCode() auf allen Unterfeldern aufruft, bis ein equals()-Vergleich auf einem nicht-Feld möglich ist.
Was heißt das nun für unsere equals()/hashCode()-Methode? Üblich ist der Einsatz von Arrays.equals() und nicht von Arrays.deepEquals() genauso wie Arrays.hashCode() üblicher als Arrays.deepHashCode() ist.
Das folgende Beispiel zeigt das in der Anwendung. Die Methoden wurden von Eclipse generiert und etwas kompakter geschrieben:
com/tutego/insel/object/hashcode/Chess.java, Chess
char[][] chessboard;
@Override public int hashCode()
{
return 31 + Arrays.hashCode( chessboard );
}
@Override public boolean equals( Object obj )
{
if ( this == obj )
return true;
if ( obj == null )
return false;
if ( getClass() != obj.getClass() )
return false;
if ( ! Arrays.equals( chessboard, ((Chess) obj).chessboard ) )
return false;
return true;
}
Labels: Insel

0 Antwort(en) auf ›equals()/hashCode() tief oder flach und mehrdimensionale Arrays‹
Kommentar veröffentlichen