Paweł był blisko, a i ja tworzyłem to zadanie z myślą panu J Blochu. Problem z kodem jest jednak troszkę inny. Pisząc metodę equals musi ona spełniać kilka podstawowych zasad. Jedną z nich jest symetryczność, czyli a.equals(b) == b.equals(a).
Przy dziedziczeniu oznacza to, że dobrze by było żeby jeżeli b rozszerza a to działanie equals w b uwzględnia ten fakt. Dodatkowo mamy tu zasadę Liskov, która mówi, że pod klasa powinna zachowywać się jak nad klasa. Czyli b powinno być w stanie porównać się z a tak jakby było a.
Ok w czym problem. Otóż nigdy nie będzie wywołane tak naprawdę porównanie ColorPoint. ColorPoint jest instancją Point zatem niezależnie jaki obiekt (ColorPoint, czy Point) będziemy porównywać to zostanie zwrócony wynik z linii 79.
Prawidłowa implementacja powinna wyglądać w następujący sposób:
Listing 1. Prawidłowa implementacja metody ColorPoint.equals
@Override public boolean equals(Object obj) { if (this == obj) return true; if (!(obj instanceof Point)) return false; if (obj instanceof ColorPoint){ ColorPoint p = (ColorPoint) obj; return super.equals(obj) && this.color.equals(p.color); } if (obj instanceof Point) return super.equals(obj); return false; }
W tym przypadku najpierw sprawdzimy czy obiekt należy do bardziej szczegółowej klasy, a dopiero potem czy jest bardziej ogólny. Dobrze napisana metoda equals powinna tego typu sprawdzenia wykonywać od liścia do korzenia.
Oj Koziołku, w ten sposób nadal możesz złamać symetryczność metody equals (czyli jej kontrakt).
Wyobraź sobie, że teraz napiszę klasę dziedziczącą z ColorPoint, np. tak:
public class TimeColorPoint extends ColorPoint {
private Date creationDate = new Date();
//Pomijamy to co zbędne
public boolean equals(Object obj) {
//pomijamy sprawdzanie nulla
if (obj.getClass() != this.getClass()) {
return false;
}
//sprawdzamy super.equals i dodane pole „creationDate”.
}
Teraz możemy zrobić sobie taki TimeColorPoint i taki ColorPoint, że colorPoint.equals(timePoint) daje TRUE, a timePoint.equals(colorPoint) daje FALSE.
Upieram się przy porównywaniu klas, a nie używaniu „instanceof” 🙂
Pozdrawiam