Angenommen, Sie sind Erstellen einer Funktion, um eine Instanz des aktuellen Typs zurückzugeben. Gibt es eine Möglichkeit, die Typvariable T auf den genauen Untertyp verweisen zu lassen (also sollte sich T auf B in Klasse B beziehen)?
class A { <T extends A> void foo(); } class B extends A { @Override T foo(); }
Um auf der Antwort von StriplingWarrior aufzubauen, muss die Das folgende Design ist erforderlich (eine Formel für eine hierarchische Fluent Builder-API):
Erstens eine abstrakte Basisklasse (oder Schnittstelle), die den Vertrag für herstellt Abrufen des Laufzeittyps einer Instanz, die die Klasse erweitert:
/** * @param <SELF> The runtime type of the implementer. */ abstract class SelfTyped<SELF extends SelfTyped<SELF>> { /** * @return This instance. */ abstract SELF self(); }
Zwischenerweiternde Klassen müssen abstrakt sein und den rekursiven Typparameter SELF beibehalten:
public abstract class MyBaseClass<SELF extends MyBaseClass<SELF>> extends SelfTyped<SELF> { MyBaseClass() { } public SELF baseMethod() { //logic return self(); } }
Weiter abgeleitete Klassen können dem gleichen folgen Muster. Allerdings kann keine dieser Klassen direkt als Variablentypen verwendet werden, ohne Rohtypen oder Platzhalter zu verwenden (was den Zweck des Musters untergräbt). Zum Beispiel (wenn MyClass nicht abstrakt wäre):
//wrong: raw type warning MyBaseClass mbc = new MyBaseClass().baseMethod(); //wrong: type argument is not within the bounds of SELF MyBaseClass<MyBaseClass> mbc2 = new MyBaseClass<MyBaseClass>().baseMethod(); //wrong: no way to correctly declare the type, as its parameter is recursive! MyBaseClass<MyBaseClass<MyBaseClass>> mbc3 = new MyBaseClass<MyBaseClass<MyBaseClass>>().baseMethod();
Aus diesem Grund werden diese Klassen als „Mittelstufe“ bezeichnet und sollten alle als abstrakt deklariert werden. Um die Schleife abzuschließen und das Muster zu nutzen, sind „Leaf“-Klassen erforderlich, die den geerbten Typparameter SELF mit seinem Typ auflösen und self() implementieren. Um einen Vertragsbruch zu verhindern, sollten sie auch als endgültig markiert werden:
public final class MyLeafClass extends MyBaseClass<MyLeafClass> { @Override MyLeafClass self() { return this; } public MyLeafClass leafMethod() { //logic return self(); //could also just return this } }
Die Verwendung solcher Klassen macht das Muster verwendbar:
MyLeafClass mlc = new MyLeafClass().baseMethod().leafMethod(); AnotherLeafClass alc = new AnotherLeafClass().baseMethod().anotherLeafMethod();
Der Hauptvorteil davon besteht darin, dass Methodenaufrufe dies können in der Klassenhierarchie nach oben und unten verkettet werden und dabei den gleichen spezifischen Rückgabetyp beibehalten.
Das obige ist der detaillierte Inhalt vonWie kann ich mithilfe einer Typvariablen in Java auf den aktuellen Typ verweisen?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!