次のように仮定します。現在の型のインスタンスを返す関数を作成します。型変数 T が正確なサブタイプを参照するようにする方法はありますか (つまり、T はクラス B の B を参照する必要があります)?
class A { <T extends A> void foo(); } class B extends A { @Override T foo(); }
StriplingWarrior の応答に基づいて構築するには、次の設計が必要です (階層型の Fluent ビルダー 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() を実装するパターンを利用するために必要です。コントラクトの違反を防ぐために、それらも最終としてマークする必要があります:
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 中国語 Web サイトの他の関連記事を参照してください。