2017-01-16 4 views
17

誰かが次のような動作を私に説明できますか?addAll()コンパイラを使用したArrayListは、ジェネリックで異なる動作を示します

私はXのリストを持っており、addAll()メソッドを使用して要素を追加しています。これらの要素は、ジェネリック型を使用するメソッドによって返されます。メソッドgetA()は、Aをクラスとして返す< T extends A >を返します。方法getI()は、Iを持つ< T extends I >を返します(以下のコードを参照)。

差異:listX.addAll(getA())コンパイルエラーが発生しましたが、listX.addAll(getI())がコンパイルされます(要素がキャストされたときにランタイムエラーが発生します。X)。

Simpifiedコード:

interface I {} 
class A implements I {} 

class X {} 

public void test() { 
    List<X> listX = new ArrayList<>(); 
    listX.addAll(getA()); 

    listX.addAll(getI()); 
    for (X x : listX) {} 
} 
public <T extends A> List<T> getA() { 
    return new ArrayList<>(); 
} 
public <T extends I> List<T> getI() { 
    return new ArrayList<>(); 
} 

私は何かが足りないのですか?私はコンパイルエラーを2回も受け取らないといけませんか?

Java 8ではこの動作が新しいようですが、以下のバージョンではどちらの場合でもコンパイルエラーが発生しています。

+2

を延長しない、Xで何かを返すことができませんか?どのコンパイラを使用していますか? – shmosel

+0

はい、複数のエラーメッセージが必要です。 –

+0

私はBを使ってテストしました。私はEclipseコンパイラを使用しましたが、この問題は他のJava 8コンパイラでも見られます。 – firecat

答えて

7

listX.addAll(getA());Xのサブクラスがありません。サブクラスはAであるため、コンパイルできません。

listX.addAll(getI());Xのサブクラスがあり、Iも実装できるため、コンパイルできません。

+4

'X'のサブクラスは' I'を実装していて、単に ''ではなく' 'として宣言されるべきです。 –

+1

私には意味があります。 –

+2

@NicolasFilotto 'getI()'は 'T'が' X'を拡張していると宣言していません。 'T'のリストを返すだけで、呼び出し元がどのような型かを判断させることができます。型引数が 'I'と互換性があることを確実にするのは呼び出し側の責任です。これは' X'の場合です。 – shmosel

8

私は次のように質問とShmoselの答えを簡素化したいと思います:

interface I {} 
class A implements I {} 

class X {} 

public void test() { 
    X temp = getI(); // compiles 
    X temp2 = getA(); // does not compile 
} 

public <T extends I> T getI() { 
    return null; 
} 
public <T extends A> T getA() { 
    return null; 
} 

GETI()潜在的にXを拡張し、それがコンパイル理由である、私を実装して何かを返すことができます。通常、実際に返される型は、関数に渡される引数など、何かに依存します。それはAを拡張して、何かを返すので、

下駄は() 'B'が入って来ないX.

関連する問題