摘自Joshua Bloch的《有效的Java 》,

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

    String[] is subtype of Object[]

    不变量简单地表示与X是否是Y的子类型无关,

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

我的问题是,为什么在Java中决定使数组协变?还有其他像Why are Arrays invariant, but Lists covariant?这样的SO帖子,但它们似乎都集中在Scala上,我无法跟上.

推荐答案

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

Java相关问答推荐

如何专门保存数据而不显示在jTable中?

Saxon 9:如何从Java扩展函数中的net.sf.saxon.expr. XPathContent中获取声明的变量

BiPredicate和如何使用它

Springdoc Whitelabel Error Page with Spring V3

如何调用Firebase Realtime Database中的子图像列表到android studio中的回收器视图?

@org.springframework.beans.factory.annotation.Autowired(required=true)-注入点有以下注释:-SpringBoot

使用意向过滤器从另一个应用程序启动服务

第三方Jar pom.xml

每次FXMLLoader调用ApplationConext.getBean(类)时创建@Component的新实例

如何只修改父类ChroniclerView位置0处的第一个嵌套ChroniclerView(child)元素?

如何使用log4j2(Json)记录由";异常引起的所有";?

Java页面筛选器问题

如何在盒子的顶部和底部创建两张不同图片(大小相同)的盒子?

是否有一个Java Future实现可以在池繁忙时在调用者线程中执行?

如果List是一个抽象接口,那么Collectors.toList()如何处理流呢?

未调用OnBackPressedCallback-Activitiy立即终止

将BlockingQueue+守护程序线程替换为执行器

在Java中使用StorageReference将数据从Firebase存储添加到数组列表

OAuth:登录后无法查看Google邮箱地址

Java中的一个错误';s stdlib SocksSocketImpl?