通过维基百科:
Early versions of Java and C# did not include generics (a.k.a. parametric polymorphism).
In such a setting, making arrays invariant rules out useful polymorphic programs.
For example, consider writing a function to shuffle an array, or a function that tests two arrays for equality using the Object.equals
method on the elements. The implementation does not depend on the exact type of element stored in the array, so it should be possible to write a single function that works on all types of arrays. It is easy to implement functions of type
boolean equalArrays (Object[] a1, Object[] a2);
void shuffleArray(Object[] a);
However, if array types were treated as invariant, it would only be possible to call these functions on an array of exactly the type Object[]
. One could not, for example, shuffle an array of strings.
Therefore, both Java and C# treat array types covariantly. For instance, in C# string[]
is a subtype of object[]
, and in Java String[]
is a subtype of Object[]
.
这段文字回答了一个问题:“为什么数组是协变的?”或者更准确地说,“为什么在当时数组被设计成协变的?” 当引入泛型时,出于Jon Skeet在
这篇回答中指出的原因,它们故意没有被设计成协变。
No, a List<Dog>
is not a List<Animal>
. Consider what you can do with a List<Animal>
- you can add any animal to it... including a cat. Now, can you logically add a cat to a litter of puppies? Absolutely not.
// 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?
Suddenly you have a very confused cat.
维基百科文章中描述数组协变的原始动机并不适用于泛型,因为通配符使得协变(和逆变)的表达成为可能,例如:
boolean equalLists(List<?> l1, List<?> l2);
void shuffleList(List<?> l);
LinkedList
。 - Paul Bellora