Via 维基百科 http://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29#Covariant_arrays_in_Java_and_C.23:
Java 和 C# 的早期版本不包含泛型(又名参数多态性)。
在这种情况下,使数组不变会排除有用的多态程序。
例如,考虑编写一个函数来打乱数组,或者编写一个使用以下函数测试两个数组是否相等的函数Object.equals
元素上的方法。该实现不依赖于数组中存储的元素的确切类型,因此应该可以编写一个适用于所有类型数组的函数。很容易实现类型的功能
boolean equalArrays (Object[] a1, Object[] a2);
void shuffleArray(Object[] a);
但是,如果数组类型被视为不变,则只能在类型完全相同的数组上调用这些函数Object[]
。例如,人们无法对一组字符串进行打乱。
因此,Java 和 C# 都以协变方式对待数组类型。例如,在 C# 中string[]
是一个子类型object[]
,而在 Java 中String[]
是一个子类型Object[]
.
这回答了“为什么数组是协变的?”这个问题,或者更准确地说,“为什么were数组变得协变当时?"
当引入泛型时,由于中指出的原因,它们故意不成为协变的乔恩·斯基特的回答 https://stackoverflow.com/a/2745301/697449:
No, a List<Dog>
不是一个List<Animal>
。考虑一下你可以用List<Animal>
- 您可以添加任何动物......包括猫。现在,你能合乎逻辑地将一只猫添加到一窝小狗中吗?绝对不。
// 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困惑的猫。
维基百科文章中描述的使数组协变的最初动机并不适用于泛型,因为通配符 http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html使协方差(和逆变)的表达成为可能,例如:
boolean equalLists(List<?> l1, List<?> l2);
void shuffleList(List<?> l);