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.


Copyright © 2025 Thomas Smits