通过wikipedia:
Java和C#的早期版本不包括泛型(也称为参数多态性).
在这种情况下,使数组不变会排除有用的多态程序.
例如,考虑编写一个混洗数组的函数,或者编写一个使用元素上的Object.equals
方法测试两个数组是否相等的函数.实现不依赖于存储在数组中的元素的确切类型,因此应该可以编写适用于所有类型的数组的单个函数.类型的函数很容易实现
boolean equalArrays (Object[] a1, Object[] a2);
void shuffleArray(Object[] a);
但是,如果将数组类型视为不变数组,则只能在类型正好为Object[]
的数组上调用这些函数.例如,人们不能对字符串数组进行混洗.
因此,Java和C#都以协变的方式处理数组类型.例如,在C#中,string[]
是object[]
的子类型,而在Java中,String[]
是Object[]
的子类型.
这回答了问题"为什么数组是协变的?",或者更准确地说,"为什么were个数组成为协变at the time?"
当引入泛型时,出于this answer by Jon Skeet中指出的原因,它们被有意地不协变:
不,List<Dog>
不是List<Animal>
.想一想你能用List<Animal>
做什么--你可以给它添加任何动物……包括一只cat .现在,你能合乎逻辑地给一窝小狗加一只cat 吗?绝对不行.
// Illegal code - because otherwise life would be Bad
List<Dog> dogs = new List<Dog>();
List<Animal> animals = dogs; // Awooga awooga
animals.add(new Cat());
Dog dog = dogs.get(0); // This should be safe, right?
突然你有了一只very岁的cat .
维基百科文章中描述的使数组协变的最初动机不适用于泛型,因为wildcards使协变(和逆变)的表达成为可能,例如:
boolean equalLists(List<?> l1, List<?> l2);
void shuffleList(List<?> l);