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

2022-09-03 02:21:35

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

我有一个列表,并使用该方法添加元素。这些元素由使用泛型类型的方法返回。方法以类的形式返回。方法以接口的形式返回(请参阅下面的代码)。XaddAll()getA()< T extends A >AgetI()< 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中似乎是新的,在两种情况下,我都得到了编译器错误。


答案 1

我想简化这个问题和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 的东西,而 A 不扩展 X。


答案 2

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

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


推荐