为什么数组是协变的,而泛型是不变的? [英] Why are arrays covariant but generics are invariant?

查看:26
本文介绍了为什么数组是协变的,而泛型是不变的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

来自 Joshua Bloch 的 Effective Java,

From Effective Java by Joshua Bloch,

  1. 数组在两个重要方面与泛型类型不同.第一个数组是协变的.泛型是不变的.
  2. 协变仅仅意味着如果 X 是 Y 的子类型,那么 X[] 也将是 Y[] 的子类型.数组是协变的 因为字符串是对象的子类型所以

  1. Arrays differ from generic type in two important ways. First arrays are covariant. Generics are invariant.
  2. Covariant simply means if X is subtype of Y then X[] will also be sub type of Y[]. Arrays are covariant As string is subtype of Object So

String[] 是 Object[] 的子类型

不变只是意味着不考虑 X 是否是 Y 的子类型,

Invariant simply means irrespective of X being subtype of Y or not ,

 List<X> will not be subType of List<Y>.

我的问题是为什么决定在 Java 中使数组协变?还有其他 SO 帖子,例如 为什么数组是不变的,但列表是协变的?,但他们似乎专注于 Scala,我无法跟上.

My question is why the decision to make arrays covariant in Java? There are other SO posts such as Why are Arrays invariant, but Lists covariant?, but they seem to be focussed on Scala and I am not able to follow.

推荐答案

通过 维基百科:

Java 和 C# 的早期版本不包括泛型(也称为参数多态).

Early versions of Java and C# did not include generics (a.k.a. parametric polymorphism).

在这种情况下,使数组保持不变会排除有用的多态程序.例如,考虑编写一个函数来对数组进行混洗,或者编写一个使用 Object.equals 方法在元素上测试两个数组是否相等的函数.该实现不依赖于存储在数组中的元素的确切类型,因此应该可以编写一个适用于所有类型数组的函数.很容易实现类型的功能

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);

但是,如果将数组类型视为不变的,则只能在类型为 Object[] 的数组上调用这些函数.例如,不能打乱字符串数组.

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.

因此,Java 和 C# 都协变地处理数组类型.例如,在 C# 中 string[]object[] 的子类型,而在 Java 中 String[] 的子类型对象[].

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[].

这回答了为什么数组是协变的?"的问题,或者更准确地说,为什么在当时使数组成为协变的?"

This answers the question "Why are arrays covariant?", or more accurately, "Why were arrays made covariant at the time?"

当引入泛型时,由于Jon Skeet 的这个回答中指出的原因,它们故意没有成为协变:

When generics were introduced, they were purposefully not made covariant for reasons pointed out in this answer by Jon Skeet:

不,List 不是 List.考虑一下您可以使用 List 做什么 - 您可以向其中添加任何动物……包括猫.现在,你能合乎逻辑地在一窝小狗中添加一只猫吗?绝对不会.

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.

维基百科文章中描述的使数组协变的最初动机不适用于泛型,因为 通配符 使协方差(和逆变)的表达成为可能,例如:

The original motivation for making arrays covariant described in the wikipedia article didn't apply to generics because wildcards made the expression of covariance (and contravariance) possible, for example:

boolean equalLists(List<?> l1, List<?> l2);
void shuffleList(List<?> l);

这篇关于为什么数组是协变的,而泛型是不变的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆