18

抽象クラスを使用して、サブクラスに対して「this」を返すメソッドを定義したいと思います。

public abstract class Foo {
    ...
    public <T extends Foo> T eat(String eatCake) {
        ...
        return this;
    }
}  

public class CakeEater extends Foo {}

私は次のようなことができるようになりたいです:

CakeEater phil = new CakeEater();
phil.eat("wacky cake").eat("chocolate cake").eat("banana bread");

おそらくバナナブレッドは、「ケーキではありません!」というメッセージとともにIllegalArgumentExceptionをスローします。

4

4 に答える 4

27
public abstract class Foo<T extends Foo<T>>  // see ColinD's comment
{
    public T eat(String eatCake) 
    {
        return (T)this;
    }
}

public class CakeEater extends Foo<CakeEater> 
{
    public void f(){}
}

編集

サブクラスが静的型付けでチェックできる以上の特定の方法で動作することを要求するのに問題はありません。私たちは常にそれを行っています-サブクラスの書き方を指定するための平易な英語のページとページ。

共変の戻り型を使用する他の提案されたソリューションは、同じことを行う必要があります-サブクラスの実装者に、平易な英語で、の型を返すように要求しthisます。その要件は、静的型付けでは指定できません。

于 2010-07-19T20:24:53.713 に答える
22

クライアントの観点からの趣味の良いアプローチ(通常はあなたが取りたいものです)は、Michael Barkerが指摘するように、ジェネリックスをサポートするために追加された共変リターンタイプを使用することです。

getThis少し味わいが少ないですが、キャストがメソッドを追加することで味わいが増します。

protected abstract T getThis();

public <T extends Foo> T eat(String eatCake) {
    ...
    return getThis();
}
于 2010-07-19T21:53:33.443 に答える
8

ジェネリックは必要ないと思います。Java5(およびそれ以降)には共変の戻り型があります。例:

public abstract class Foo {
    ...
    public Foo eat(String eatCake) {
        ...
        return this;
    }
}  

public class CakeEater extends Foo {

    public CakeEater eat(String eatCake) {
        return this;
    }
}
于 2010-07-19T20:12:07.640 に答える
0

同様の動作を実現するために以前に使用したアプローチは、サブクラスにその型を(生成された)親型のコンストラクターに渡すことです。免責事項として、私はその場でサブクラスを生成していました。継承は、コード生成を単純に保つためのちょっとしたごまかしでした。いつものように、私の最初の本能は、extends関係を完全に削除しようとすることです。

于 2010-07-20T00:24:36.460 に答える