2016-07-24 13 views
26

Ich möchte ermitteln können, ob eine Basisklassenmethode von einer Unterklasse speziell überschrieben wurde, weil vor dem Aufruf und den meisten Unterklassen eine teure Einrichtung erforderlich ist unser System überschreibt es nicht. Kann es getestet werden, indem Reflection bereitgestellte Methoden behandelt? Oder gibt es eine andere Möglichkeit zu testen, ob eine Klassenmethode überschrieben wird?Gibt es eine Möglichkeit festzustellen, ob eine Methode in einer Java-Klasse überschrieben wurde

z.B.

class BaseClass { 
    void aMethod() { // don nothing } 

    protected boolean aMethodHasBeenOverridden() { 
     return(// determine if aMethod has been overridden by a subclass); 
    } 
} 

Antwort

30

Sie können durch die Untersuchung der deklarierte Klasse Ihrer Methode mit Reflexion tun:

class Base { 
    public void foo() {} 
    public void bar() {} 
} 
class Derived extends Base { 
    @Override 
    public void bar() {} 
} 
... 
Method mfoo = Derived.class.getMethod("foo"); 
boolean ovrFoo = mfoo.getDeclaringClass() != Base.class; 
Method mbar = Derived.class.getMethod("bar"); 
boolean ovrBar = mbar.getDeclaringClass() != Base.class; 
System.out.println("Have override for foo: "+ovrFoo); 
System.out.println("Have override for bar: "+ovrBar); 

Drucke

Have override for foo: false 
Have override for bar: true 

Demo.

+0

Problem, wenn das Verfahren auf einer Zwischenklasse zwischen der Basisklasse und der Blatt Klasse überschrieben wird. – chrylis

+1

@chrylis Danke, dass du das herausgibst. Der Vergleich der deklarierenden Klasse mit 'Base.class' löst dieses Problem. – dasblinkenlight

+0

Minor note - C++ verwendet die Terminologie ** Basisklasse ** und ** abgeleitete Klasse **; Java verwendet die Terminologie ** Superklasse ** und ** Unterklasse **. – Nayuki

2

Der Ansatz, den ich nehmen würde, ist zu nur diese Methode gibt es wenn die Sub Klasse benötigt es durch Überschreiben der Methode, die es in einer abstrakten Zwischenklasse aufruft. Hier ist, was ist das aussehen würde:

public abstract class MovingThing { 
    public void move() { 
     // walk a few feet 
    } 
} 

Jetzt ein paar Ihrer beweglichen Sachen teleportieren, aber das erfordert die Fluss Kondensatoren und andere teure Dinge aufladen, trennen, so dass aus:

public abstract class TeleportingThing extends MovingThing { 
    @Override 
    public void move() { 
     fluxCapacitor.charge(); 
     stardate.calculate(); 
     doTeleport(); 
    } 

    protected abstract void doTeleport(); 
} 

Ihre Klassen, Das teure Setup muss von der zweiten Klasse abgeleitet werden, die es enthält, während diejenigen, die nicht von der ersten Klasse abgeleitet werden können. Dieses Muster ist eine Art Dekorator und wird beispielsweise in der Servlet-API verwendet, wo die meisten Servlets etwas wie doGet() überschreiben und das Parsing auf service() belassen.

+0

Das Problem dabei ist, dass ein Implementierungsdetail (d. H. Wie die teure Einrichtung vermieden wird, wenn dies nicht unbedingt notwendig ist) die öffentliche API (d. H. Die Vererbungskette) beeinflusst. Und schlimmer, es funktioniert nur für eine * single * -Methode (zumindest in Java), weil Sie nur von einer einzelnen Basisklasse erben können. Eine 'geschützte boolesche Methode 'aMethodHasBeenOverridden()' wie in der OP-Frage zu haben, mag auf den ersten Blick weniger elegant aussehen, wäre aber eigentlich vorzuziehen, da sie keine dieser Down-Seiten hat ... – fgp

+0

@fgp Putting that Methode in die Klasse hat genau das gleiche Problem beim Aussetzen der öffentlichen API, und meine Technik kann auf jede Menge potenziell überschreibbarer Methoden angewendet werden. – chrylis

+0

Sie Methode koppelt die Wahl der Basisklasse mit ob doTeleport() überschrieben wird, also, wenn Sie zwei solche Methoden haben und eins außer dem anderen außer Kraft setzen möchten, wie würden Sie das tun? – fgp

9

Dies kann unter Aufruf getClass().getDeclaredMethod("aMethod"), die nur etwas zurückgibt, wenn die Klasse this es deklariert.

Hier ist eine Implementierung Ihrer Methode:

/** 
* @return true if the instance's class overrode aMethod 
*/ 
protected boolean aMethodHasBeenOverridden() { 
    try { 
     return getClass() != A.class && getClass().getDeclaredMethod("aMethod") != null; 
    } catch (NoSuchMethodException | SecurityException e) { 
     return false; 
    } 
}