2016-08-10 8 views
14

のは、私たちは、このようにいくつかのテスト・インタフェース/クラスを持っているとしましょう:Javaの非ジェネリックとしてインタフェースの汎用メソッドを実装できるのはなぜですか?

abstract class Plant { 
    public abstract String getName(); 
} 

interface Eatable { } 

class Apple extends Plant implements Eatable { 
    @Override 
    public String getName() { 
     return "Apple"; 
    } 
} 

class Rose extends Plant { 
    @Override 
    public String getName() { 
     return "Rose"; 
    } 
} 

interface Animal { 
    <T extends Plant & Eatable> void eat(T plant); 
} 

あなたはAnimal.eat、制約のある一般的な方法で見ることができます。細かいコンパイル

class Human implements Animal { 
    @Override 
    public void eat(Plant plant) { 
    } 
} 

:今、私はこのような私のHumanクラスを持っています。 Eatableインターフェイスが失われているため、Human.eatのサイズがAnimal.eatよりも小さいことがわかります。

Q1:なぜコンパイラはこの不一致について不平を言っていませんか?

Q2:PlantからPlant&Eatableダウングレードした場合は、それがeat(Object plant)に文句を言う理由は、コンパイラのために許容できるのですか?

+2

使用しているJavaのバージョン。 eclipseでJava 1.8を使用すると、コンパイル時にエラーが発生することがあります。 – Codebender

+0

Intellij IDEAの@ CodeBender Java8。 –

+2

@Codebender私はこれをコンパイルする問題はありません。 https://ideone.com/7xUcZn – flakes

答えて

12

Lesson: Generics by Gilad Bracha 彼に従って

public static <T extends Object & Comparable<? super T>> T max(Collection<T> coll) 

これは構文T1 & T2 ... Tnに&を使用して、タイプパラメータに を複数の境界を与えるの一例です。複数の 境界を持つ型変数は、 境界にリストされたすべての型のサブタイプであることが知られています。複数の境界が使用される場合、 バインドで言及された最初の型が、型変数の消去として使用されます。

ので、あなたの例<T extends Plant & Eatable> void eat(T plant);は、あなたがそれを上書きするときに入れ制約にの実装をしたいのであれば、コンパイラ

0

アーメドの答えを文句はありませんが、やり方によって、権利でvoid eat(Plant plant);に消去されます、そして、

interface Animal<T extends Plant & Eatable> { 
    void eat(T plant); 
} 

あなたは型情報を提供せずに動物のインタフェースを実装している場合、コンパイラはに少なくとも驚きのポリシーを使用します:動物のインタフェースは、このようにそれを宣言する必要があります植物型としてTを推論する。しかし、必要な型情報を提供すれば、コンパイラは正常に動作します。

class Human implements Animal<Rose> // won't compile 
class Human implements Animal<Apple> // compile 
関連する問題