任何简单的方法来解释为什么我不能做List<Animal> animals = new ArrayList<Dog>()?

2022-09-02 00:00:49

我知道为什么人们不应该这样做。但是有没有办法向外行解释为什么这是不可能的。你可以很容易地向外行解释这一点:。狗是一种动物,但狗的清单不是动物的清单。Animal animal = new Dog();


答案 1

想象一下,你创建了一个列表。然后,将其声明为List<Animal>并将其交给同事。他不无理地相信他可以把一只猫放进去。

然后他把它还给你,你现在有一份的清单,中间有一只猫。混乱接踵而至。

请务必注意,由于列表的可变性,存在此限制。例如,在Scala中,您可以声明列表是动物列表。这是因为 Scala 列表(默认情况下)是不可变的,因此将 Cat 添加到 Dog 列表中将为您提供新的动物列表。


答案 2

您正在寻找的答案与称为协方差和逆方差的概念有关。某些语言支持这些(例如,.NET 4 添加了支持),但一些基本问题通过如下代码演示:

List<Animal> animals = new List<Dog>();

animals.Add(myDog); // works fine - this is a list of Dogs
animals.Add(myCat); // would compile fine if this were allowed, but would crash!

由于 Cat 源自动物,因此编译时检查会建议将其添加到 List 中。但是,在运行时,您无法将猫添加到狗列表中!

因此,尽管这在直觉上看起来很简单,但这些问题实际上非常复杂。

这里有一个关于.NET 4中协/逆变的MSDN概述:http://msdn.microsoft.com/en-us/library/dd799517(VS.100).aspx - 它也适用于java,尽管我不知道Java的支持是什么样的。