2017-12-14 8 views
2

共変戻りタイプのメソッドをオーバーライドできますが、デフォルトのメソッドを共変戻りタイプでオーバーライドすることはできますか?次の例では、デフォルトのメソッドを書き直すことなくgetFirstLegをオーバーライドしたいと考えていますが、Javaではこれを許可していません。また、多くのパラメータがあり、Animalが多くの場所で使用されているため、Animalを汎用インターフェイスにしたくないです。デフォルトメソッドの共変戻りタイプ

更新:次のコードはコンパイルされますが、新しい問題はDuckがもはやAnimalではないということです。

interface Leg { 
} 

interface AnimalGeneric<T extends Leg> { 
    List<? extends T> getLegs(); 

    default T getFirstLeg() { 
     return getLegs().get(0); 
    } 
} 

abstract class AnimalImpl<T extends Leg> implements AnimalGeneric<T> { 
    private List<T> legs; 

    @Override 
    public List<T> getLegs() { 
     return legs; 
    } 
} 

interface Animal extends AnimalGeneric<Leg> { 
    //empty 
} 

interface BirdLeg extends Leg { 
} 

interface BirdGeneric<T extends BirdLeg> extends AnimalGeneric<T> { 
} 

class BirdImpl<T extends BirdLeg> extends AnimalImpl<T> implements BirdGeneric<T> { 
} 

interface Bird extends BirdGeneric<BirdLeg> { 
    //empty 
} 

interface DuckLeg extends BirdLeg { 
} 

class DuckImpl extends BirdImpl<DuckLeg> implements Duck { 
} 

interface Duck extends BirdGeneric<DuckLeg> { 
} 

答えて

0

はい、Javaには継承されたメソッドの共変な戻り値の型があります。しかし、ここでの問題は、getFirstLegdefaultメソッドであるという事実ではなく、それはJavaのジェネリックが共変ではないということです。彼らは不変です。私。たとえDuckLegLegであっても、List<DuckLeg>List<? extends Leg>ではありません。

しかし、Animalインターフェイスを汎用にすることで回避できます。これにより、typeパラメータがサブインターフェイスに基づいて変更できるようになります。

interface Animal<T extends Leg> { 
    List<T> getLegs(); 

    default T getFirstLeg() { 
     return getLegs().get(0); 
    } 
} 

その後Duckも、型パラメータを持っていますが、もう何をオーバーライドする必要はありません。型引数DuckLegTに割り当てられます。

interface Duck extends Animal<DuckLeg> { 
    // able to remove the override of getLegs 
    //@Override 
    //List<DuckLeg> getLegs(); //covariant return type 

    // able to remove the override of getFirstLeg 
    //@Override 
    //DuckLeg getFirstLeg(); //I do not want to rewrite this method 
} 

次に、あなたのDuckImplクラスが適切にすべてのものを継承し、あなたは「抽象的ではないとし、抽象メソッドオーバーライドしません」を取得しませんエラーが発生しました。

もちろん、空の宣言がDuckの場合は、まったく必要ない場合があります。 DuckImplAnimal<DuckLeg>を実装してください。

class DuckImpl extends AnimalImpl<DuckLeg> implements Animal<DuckLeg> { 

} 
+0

は私の記事で最後の文を参照してください。私はAnimal(または他の広く使われているインターフェース)を一般化することに懸念を抱いています。なぜなら、パラメータを変更したい場合は、多くの場所を変更する必要があるからです。 – Fan

+0

リストはリスト<ですか? Leg>を拡張し、List <? DuckLeg> List <?脚を伸ばす>? – Fan

+0

Javaのジェネリックは不変であるため、問題を正確に解決するには、 'Animal'ジェネリックを使ってください。また、 'List <? extends DuckLeg> '' List <? 'にすることはできません。ワイルドカードは特定の未知の型を表すため、Leg> 'を拡張します。 'List <? extends DuckLeg>は 'List
'を表すことができ、 'List <? extends Leg>は 'List 'を表すことができます。不一致の可能性があるため、コンパイラはワイルドカードで共変ジェネリックスを禁止する必要があります。 – rgettman

0

共分散が必要な場合は、Legと入力します。ほとんどのコードを削除することができます。

これは、コンパイルされます。

interface Leg { 
} 

interface Animal<T extends Leg> { 
    List<T> getLegs(); 

    default T getFirstLeg() { 
     return getLegs().get(0); 
    } 
} 

abstract class AnimalImpl<T extends Leg> implements Animal<T> { 
    private List<T> legs; 

    @Override 
    public List<T> getLegs() { 
     return legs; 
    } 
} 

interface DuckLeg extends Leg { 
} 

interface Duck extends Animal<DuckLeg> { 
} 

class DuckImpl extends AnimalImpl<DuckLeg> implements Duck { 
    // no errors 
} 
+0

私の記事の最後の文章をご覧ください。私はAnimal(または他の広く使われているインターフェース)を一般化することに懸念を抱いています。なぜなら、パラメータを変更したい場合は、多くの場所を変更する必要があるからです。 – Fan

関連する問題