Java中的泛型

Java中的泛型,java,generics,Java,Generics,我今天遇到了一些奇怪的事情。请看以下代码片段: List <Rectangle> test1 = new LinkedList<Rectangle>(); List <Shape> test2 = test1; //Compiler Error; List test1=newlinkedlist(); 列表test2=test1//编译错误; 这当然是假设类Rectangle是Shape的子类。 有人能给我解释一下为什么这是一个错误吗?这是一个常见的混淆源

我今天遇到了一些奇怪的事情。请看以下代码片段:

List <Rectangle> test1 = new LinkedList<Rectangle>();
List <Shape> test2 = test1; //Compiler Error;
List test1=newlinkedlist();
列表test2=test1//编译错误;
这当然是假设类Rectangle是Shape的子类。
有人能给我解释一下为什么这是一个错误吗?

这是一个常见的混淆源-泛型在Java中是不协变的

有关这一点的详细解释,请参见:

虽然你可能会发现 将收藏视为一种艺术 对于数组的抽象,它们有一些 集合所具有的特殊属性 不Java语言中的数组是 协变的,也就是说如果 整数扩展了它所指定的数字 则不仅是一个整数 也是一个数字,但整数[]是 还有一个数字[],您可以自由 传递或分配一个整数[],其中 电话号码[]。(更多 形式上,如果Number是 整数,则数字[]是超类型 整数[]。您可能会认为 泛型类型也是如此 --该列表是列表的超类型,您可以传递 列出列表所在的位置 预期。不幸的是,事实并非如此 那样做


你需要使用通配符。像这样:

List<Rectangle> test1 = new LinkedList<Rectangle>();
List<? extends Shape> test2 = test1;
List test1=newlinkedlist();

列表如果此代码起作用,您可以通过插入
test2
a
Circle
——从而彻底打破
test1
所做的保证,即只有
矩形
s将被插入其中

一般原则(与语言无关——逻辑问题——尽管违反直觉):一袋香蕉不是一袋水果。。。在一个可变对象的世界中(函数式编程世界,在这个世界中,每个对象一经创建就不可变,要简单得多!)。这是因为你可以在一袋水果中加一个苹果(因为苹果是一片水果),但你不能在一袋香蕉中加一个苹果(因为苹果不是香蕉)

顺便说一句,这与正方形不是矩形的原因非常相似(同样,在一个可变对象的世界中):因为给定一个(可变)矩形,你可以独立地改变两边,但是,给定一个正方形,你不能。(在几何学中,正方形实际上是一个矩形——但这是因为,在像函数式编程一样的几何学中,没有“改变”对象的概念!-)。

列表与列表无关。使用数组时,形状[]实际上是矩形[]的超类型,因为数组是协变的。但像List这样的集合并不是协变的。事实上,在运行时,它们都将作为List删除,当您从List、List的任何实例调用任何方法时,VM将调用List的方法,但插入一些其他代码以检查类型安全性