假設你是建立一個函數以傳回目前類型的實例。有沒有辦法讓類型變數 T 引用精確的子類型(因此 T 應該引用 B 類別中的 B)?
class A { <T extends A> void foo(); } class B extends A { @Override T foo(); }
為了建立 StriplingWarrior 的回應,需要以下設計(分層流暢建構器 API的公式):
首先,一個抽象基類(或介面),用於建立用於檢索擴展類的實例的運行時類型的契約:
/** * @param <SELF> The runtime type of the implementer. */ abstract class SelfTyped<SELF extends SelfTyped<SELF>> { /** * @return This instance. */ abstract SELF self(); }
中間擴展類必須是抽象的並維護遞歸類型參數SELF:
public abstract class MyBaseClass<SELF extends MyBaseClass<SELF>> extends SelfTyped<SELF> { MyBaseClass() { } public SELF baseMethod() { //logic return self(); } }
進一步派生的類別可以遵循相同的圖案。但是,如果不使用原始類型或通配符(這會破壞該模式的目的),這些類別都不能直接用作變數類型。例如(如果 MyClass 不是抽象的):
//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();
這就是為什麼這些類別被稱為“中間類別”,以及為什麼它們都應該被聲明為抽象的。 「葉」類別需要完成循環並使用該模式,該模式解析繼承的類型參數 SELF 及其類型並實作 self()。為了防止破壞契約,它們也應該被標記為final:
public final class MyLeafClass extends MyBaseClass<MyLeafClass> { @Override MyLeafClass self() { return this; } public MyLeafClass leafMethod() { //logic return self(); //could also just return this } }
使用這樣的類別使得模式可用:
MyLeafClass mlc = new MyLeafClass().baseMethod().leafMethod(); AnotherLeafClass alc = new AnotherLeafClass().baseMethod().anotherLeafMethod();
這樣做的主要優點是方法呼叫可以在類別層次結構中上下鏈接,同時保持相同的特定返回類型。
以上是如何在 Java 中使用類型變數引用目前型別?的詳細內容。更多資訊請關注PHP中文網其他相關文章!