使用addAll()编译器的ArrayList显示泛型的不同行为

时间:2017-01-16 09:23:55

标签: java generics java-8

有人可以向我解释以下行为吗?

我有一个X列表,并使用addAll()方法添加元素。这些元素由使用泛型类型的方法返回。方法getA()返回< T extends A >,其中A是一个类。方法getI()返回< T extends I >,其中I是一个接口(请参阅下面的代码)。

差异:使用listX.addAll(getA())我收到编译错误(正如预期的那样),但是listX.addAll(getI())编译(当元素转换为X时抛出运行时错误。)

简化代码:

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<>();
}

我错过了什么吗?我不应该两次都遇到编译错误吗?

对于Java 8来说,这种行为似乎是新的,下面的版本我在这两种情况下都遇到了编译器错误。

2 个答案:

答案 0 :(得分: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并实现I的东西,这就是它编译的原因。通常,它实际返回的类型取决于某些东西,例如传递给函数的参数。

getA()不能返回X的内容,因为它返回扩展A的内容,但不会扩展X.

答案 1 :(得分:7)

listX.addAll(getA());无法编译,因为X没有可能的子类,它们也是A的子类。

listX.addAll(getI());确实编译,因为可能有一个X的子类也实现了I