Quiz
Quiz: Equals I
public class A {
public int i;
public boolean equals(A obj) {
return ((obj != null) && (getClass() == obj.getClass())
&& (i == ((A) obj).i));
}
public int hashCode() { return i; }
public static void main(String[] args) {
A a1 = new A(); a1.i = 5;
A a2 = new A(); a2.i = 5;
Object o = a2;
System.out.println("a1.equals(a2): " + a1.equals(a2));
System.out.println("a1.equals(o): " + a1.equals(o));
}
}
a1.equals(a2): true
a1.equals(o): false
Die equals-Methode von A
ist fehlerhaft, da sie nicht die korrekte Signatur boolean equals(Object)
hat. Hierdurch wird die equals-Methode von Object
nicht (wie gewünscht) überschrieben, sondern überladen. D. h. die Klasse A
hat jetzt zwei equals-Methoden, nämlich die von Object
geerbte und die eigene. Die equals-Methode von A
ist damit überladen worden.
Wie bekannt, erfolgt der Aufruf von überladenen Methoden anhand des statischen Typs, sodass die in A
implementierte equals
-Methode für a1
und a2
benutzt wird, für a1
und o
aber die aus Object
. Da die Methode aus Object
keinerlei Rücksicht auf den Inhalt der Objekte nimmt, sondern einen einfachen ==-Vergleich durchführt, kommt es hier zu dem seltsamen Ergebnis.
Quiz: Equals II
public class A {
public int i;
public boolean equals(Object obj) {
return ((obj != null) && (getClass() == obj.getClass())
&& (i == ((A) obj).i));
}
public int hashCode() { return i; }
public static void main(String[] args) {
A a1 = new A(); a1.i = 5;
A a2 = new A(); a2.i = 5;
Object o = a2;
System.out.println("a1.equals(a2): " + a1.equals(a2));
System.out.println("a1.equals(o): " + a1.equals(o));
}
}
a1.equals(a2): true
a1.equals(o): true
Die equals-Methode von A
ist jetzt korrigiert worden und überschreibt die entsprechende Methode von Object
. Dank virtuellem Methodendaufruf funktioniert jetzt alles wie erwartet.
Quiz: Vergleich
Long l1 = 150L;
Long l2 = 200L;
l2 = l2 - 50;
System.out.println(l1 == l2);
false
Wenn man den Source-Code genauer betrachtet fällt auf, dass die Variablen l1
und l2
nicht vom primitiven Typ long
sind, sondern als Referenzvariablen auf den Wrapper-Typ Long
deklariert wurde. Es handelt sich also um Variablen, die auf echte Objekte zeigen. Die Tatsache, dass der Source-Code kein new
Statement enthält, entsteht dadurch, dass der Compiler im Rahmen des Autoboxing automatisch die Objekterzeugung für Wrapper-Typen vornimmt, wenn sie zugewiesen werden.
Wenn es sich aber um echte Objekte handelt, ist ein Vergleich mit ==
grundsätzlich falsch, wenn man die Objekte auf gleichen Inhalt hin prüfen möchte. ==
überprüft, ob die Referenzen auf dasselbe Objekt zeigen. Daher gibt das Programmfragment – trotz gleichen Inhalts von l1
und l2
false
aus, da es sich um verschiedene Objekte gleichen Inhalts handelt.