それはその悲しみとだけのように思えますが、本当に望むなら、それはできます。 したがって、ルールを少し破って、その継承者の親クラスに「通知」しましょう。
したがって、初期状態( commit )があります。
1)必要なすべてのメソッドを知っている
IChildParam
インターフェイス
2)親クラス
BaseClass
1)
ChildClass
下位
ChildClass
public interface IChildParam { int getBaseParam(); int getChildParam(); <T> T setBaseParam(int i); <T> T setChildParam(int i); }
public abstract class BaseClass implements IChildParam { private int baseParam; public int getBaseParam() { return baseParam; } public BaseClass setBaseParam(int i) { this.baseParam = i; return this; } }
public class ChildClass extends BaseClass { private int childParam; public int getChildParam() { return childParam; } public ChildClass setChildParam(int i) { this.childParam = i; return this; } }
また、
setBaseParam
setChildParam
と
setChildParam
を呼び出すための3つの可能なオプションを記述する小さなテストクラスを作成し
setChildParam
。
public class ClassTest { public static final int BASE_PARAM = 1; public static final int CHILD_PARAM = 2; @DataProvider(name = "data") public static Object[][] data() { final ChildClass item0 = (ChildClass) new ChildClass().setBaseParam(BASE_PARAM); item0.setChildParam(CHILD_PARAM); final ChildClass item1 = (ChildClass) new ChildClass().setChildParam(CHILD_PARAM).setBaseParam(BASE_PARAM); final ChildClass item2 = ((ChildClass) new ChildClass().setBaseParam(BASE_PARAM)).setChildParam(CHILD_PARAM); return new Object[][]{{item0}, {item1}, {item2}}; } @Test(dataProvider = "data") public void testChildClass(final IChildParam item) throws Exception { Assert.assertEquals(item.getBaseParam(), BASE_PARAM); Assert.assertEquals(item.getChildParam(), CHILD_PARAM); } }
そして、ここにコードのキャッチがあります
setBaseParam
メソッドを呼び出した直後に
setChildParam
メソッドを呼び出す代わりに、最初に型変換を実行してから
setChildParam
を呼び出す必要があります。 いずれにしても、
ChildClass
への明示的な型
ChildClass
が必要
ChildClass
さて、この「誤解」を修正しましょう。
最初に、インターフェイスの宣言を変更しましょう-Genericレベルをメソッドレベルからインターフェイスレベルに削除します。
public interface IChildParam<T> { int getBaseParam(); int getChildParam(); T setBaseParam(int i); T setChildParam(int i); }
次に、
BaseClass
クラスの宣言に変更を加え、「自分自身」の汎用タイプを追加します。
public abstract class BaseClass<T extends BaseClass> implements IChildParam<T> { private int baseParam; public int getBaseParam() { return baseParam; } public T setBaseParam(int i) { this.baseParam = i; return (T) this; } }
メインコードの変更の最後の手順は、子クラスの宣言を変更することです。
public class ChildClass extends BaseClass<ChildClass> { private int childParam; public int getChildParam() { return childParam; } public ChildClass setChildParam(int i) { this.childParam = i; return this; } }
さて、「流体インターフェース」をフルに使用してテスト内のコードを書き換えることを妨げるものは何もありません。
だった:
final ChildClass item0 = (ChildClass) new ChildClass().setBaseParam(BASE_PARAM); item0.setChildParam(CHILD_PARAM); final ChildClass item1 = (ChildClass) new ChildClass().setChildParam(CHILD_PARAM).setBaseParam(BASE_PARAM); final ChildClass item2 = ((ChildClass) new ChildClass().setBaseParam(BASE_PARAM)).setChildParam(CHILD_PARAM);
になりました:
final ChildClass item0 = new ChildClass().setBaseParam(BASE_PARAM); item0.setChildParam(CHILD_PARAM); final ChildClass item1 = new ChildClass().setChildParam(CHILD_PARAM).setBaseParam(BASE_PARAM); final ChildClass item2 = new ChildClass().setBaseParam(BASE_PARAM).setChildParam(CHILD_PARAM);
結果コミット
PS:もちろん、私たちは何も違反せず、親クラスは何も知らず、その相続人については無知のままでしたが...しかし、今ではメソッドから、相続人と同じ型を返すことができます。 。
UPD.0: コメントの 例が追加されました
UPD.1: コメントの 例を追加