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.