Java泛型:编译器赢得';虽然它们是兼容的,但不能推断类型

Java泛型:编译器赢得';虽然它们是兼容的,但不能推断类型,java,generics,casting,Java,Generics,Casting,我尝试将类型为SubTest的对象添加到具有泛型类型T的列表中,该泛型类型定义为。我希望它能工作,但编译器告诉我它不能将子测试转换为t。我只是看不出这里有什么问题 以下是完整的代码: public class Test<T extends Test.SubTest> { private List<T> list = new ArrayList<T>(); public void add() { list.add(new Su

我尝试将类型为
SubTest
的对象添加到具有泛型类型
T
的列表中,该泛型类型定义为
。我希望它能工作,但编译器告诉我它不能将
子测试
转换为
t
。我只是看不出这里有什么问题

以下是完整的代码:

public class Test<T extends Test.SubTest> {

    private List<T> list = new ArrayList<T>();

    public void add() {
        list.add(new SubTest()); //<- compile error here
    }

    protected static class SubTest {
    }

}
这会奏效的。但问题是:为什么它不起作用
没有不必要的强制转换?

类型参数
T
可以是
子测试
,但也可以是
子测试
的任何潜在子类。如果
T
是这样一个子类,那么您不能
子测试添加到
列表中,因为它是一个超类

因为编译器不知道
t
到底是哪个类,所以它不能允许您将
子测试
传递到
添加
;它可能违反Java泛型帮助您维护的类型安全性


转换为
T
将允许您编译它,因为可能有效的转换会告诉编译器,“我知道我在做什么,这将有效”。然而,这可能导致上述类型安全违规。这可能表现在运行时的
ClassCastException
中,类似于“无法将SubSubTest转换为SubTest”(如果
T
SubSubTest
,是
SubTest
的子类)。

因为
SubTest
T
的超类。当您将变量
l
声明为
List
类型时,您明确表示
l
的内容至少是
T
类型,并且任何客户端代码都应该能够对列表中的任何项执行
T
公开的所有操作。由于
T
可能比
SubTest
更具体,因此不能将
SubTest
实例添加到
l
,因为此实例不一定遵守
T
的约定。

这里的根本问题是
T
可能是
SubTest
的子类型,在这种情况下,将
子测试
添加到
列表
会主动破坏类型安全性。演员阵容不仅是必要的,在合理的情况下可能会失败。是的,你绝对正确!谢谢只是还没看到而已。我想我应该停止为今天编写代码,而是睡一觉;)我也在努力理解这一点。所以
List
应该是一个同质集合,其中列表中的所有元素都是相同类型的?但是,如果您声明
列表
,然后add()可以自由添加扩展
子测试
(包括
子测试
对象本身)的类的任何对象。在这种情况下,编译器确信所有元素都是相同的类型(即,
子测试
)。
list.add((T) new SubTest());