2015-06-17 7 views
19

Ich verwende eine Bibliothek, in der eine abstrakte Klasse eine konkrete Methode aus Object mit einer abstrakten Methode geerbt hat Vorrang:Warum kann eine abstrakte Klasse eine konkrete Methode außer Kraft setzen?

public abstract class A { 
    @Override 
    public abstract boolean equals(Object obj); 
} 

diese Klasse zu erweitern, ich habe die equals Methode implementieren:

public class B extends A { 
    @Override 
    public boolean equals(Object obj) { 
     return obj != null && obj.getClass() == B.class; 
    } 
} 

Warum kann eine abstrakte Methode (A::equals) eine konkrete Methode überschreiben (Object::equals)? Ich sehe das Ziel nicht.

+1

Es ist das Gegenteil hier - die Basisklasse hat eine abstrakte Methode und eine nicht abstrakte abgeleitete Klasse hat eine nicht abstrakte Methode, die die Basisklassenmethode außer Kraft setzt. – sharptooth

+1

@sharptooth Meine Frage war nicht sehr klar. Ich spreche von 'A :: equals' überschreiben 'Object :: equals' – gontard

+0

Ich denke, Sie sollten das explizit in der Frage erwähnen. Da du nur zwei deiner Klassen präsentiert hast, war ich sicher, dass es nur um sie ging. – sharptooth

Antwort

24

In diesem speziellen Beispiel macht es Sinn. Wenn Unterklassen von A in Sammlungen verwendet werden sollen, wobei equals weit verbreitet zum Lokalisieren von Objekten verwendet wird, erzwingt die A Methode equals die abstrakte Methode, dass Sie die Nicht-Standardimplementierung equals in Unterklassen A (anstelle von Verwenden der Standardimplementierung der Object-Klasse, die nur Instanzreferenzen vergleicht).

Natürlich macht Ihre vorgeschlagene Implementierung von equals in B wenig Sinn. Sie sollten die Eigenschaften der 2 B-Instanzen vergleichen, um festzustellen, ob sie gleich sind.

Dies ist eine geeignete Implementierung:

public class B extends A { 
    @Override 
    public boolean equals(Object obj) { 
     if (!(obj instanceof B)) 
      return false; 
     B other = (B) obj; 
     return this.someProperty.equals(other.someProperty) && this.secondProperty.equals(other.secondProperty); 
    } 
} 

Außerdem erinnern hashCode außer Kraft zu setzen, wenn Sie equals außer Kraft setzen (seit dem Vertrag von equals und hashCode erfordert, dass, wenn a.equals(b) == true dann a.hashCode() == b.hashCode()).

+0

Wenn 'B' keine anderen Eigenschaften hat (und keines hat' A'), die Instanzen voneinander unterscheiden, ein Umsetzung wie in der Frage könnte sinnvoll sein. Der Vergleich mit 'this.getClass()' Instanz von 'B.class' wäre korrekter, wenn Unterklassen von' B' betrachtet würden. –

+0

Ja, vielleicht ist 'B' ein Singleton – acbabis

10

In diesem Fall möchten Sie, dass Ihre Objekte ihre eigenen equals definieren, die sich vermutlich anders verhalten als die Standardimplementierung.

Sie sollten dies nicht als Funktion entfernen, sondern Funktionalität, sondern eher als erzwingen, dass die erbenden Objekte implementieren ihre eigenen.

+0

Sie sind klarsichtig, ich sah das wirklich * als Entfernen der Funktionalität *. – gontard

+0

@gontard: In diesem Fall * wollen * implementierende Klassen ihr eigenes Verhalten festlegen. Dazu müssen Sie sicherstellen, dass auf die Standardimplementierung nicht zugegriffen werden kann, damit das gewünschte Verhalten erzielt wird. – npinti

+0

Eigentlich ist es [noch erreichbar] (http://Stackoverflow.com/a/2692379/823393) aber gar nicht so einfach. – OldCurmudgeon

6

Damit können Sie erzwingen, dass eine Unterklasse eine Methode neu implementiert. Ob das eine gute Idee ist oder nicht, ist eine andere Sache. Sie würden dies nur tun, wenn Sie einen stärkeren Vertrag durchsetzen wollten als die ursprüngliche Methode. Sie sollten dann den neuen Vertrag sorgfältig dokumentieren.

3

Es heißt, Sie müssen Ihre eigene equals() Methode

1

implementieren, da alle Klassen in Java von Natur aus die Object Klasse erweitern. Die Klasse A erbt die Object#equals-Methode. Angenommen, Sie möchten einen Kompilierungsfehler erzwingen, wenn die equals-Methode nicht explizit implementiert ist, wie in diesem Beispiel example. Wenn Sie die Methode equals ohne einen Implementierungsblock abstrahieren möchten, können Sie dies tun.