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

fas*_*ava 22 java oop generics covariance

我知道为什么不应该这样做.但有没有办法向外行人解释为什么这是不可能的.你可以轻松地向外行解释:Animal animal = new Dog();.狗是一种动物,但是一系列的狗并不是动物的清单.

Bri*_*new 48

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

然后他把它还给你,你现在有了一份的名单,其中有一只.随之而来的是混乱.

值得注意的是,由于列表的可变性,这种限制是存在的.在斯卡拉(例如),您可以声明列表是列表的动物.那是因为Scala列表(默认情况下)是不可变的,因此将Cat添加到Dogs列表会给你一个动物列表.

  • 我喜欢这个,因为"狗和猫共同生活"的参考.虽然我认为"确保"可能意味着"随之而来".注意:一旦完全理解了这个答案,这就是进入List <?的完美网关.扩展Animal> for for和它限制你可以调用哪些方法变得更加明显(即:不能调用add()但可以调用get()等) (7认同)
  • 确实,'确定'.现在编辑. (2认同)

Dan*_*zey 8

您正在寻找的答案是与协方差和逆变的概念有关.有些语言支持这些(例如,.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!
Run Code Online (Sandbox Code Playgroud)

因为Cat将来自动物,所以编译时检查会建议它可以添加到List中.但是,在运行时,您无法将Cat添加到Dogs列表中!

因此,尽管看起来直观简单,但这些问题实际上非常复杂.

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


pol*_*nts 8

我能给出的最好的外行答案是:因为在设计泛型时,他们不想重复对Java的数组类型系统做出的相同决定,这使得它不安全.

这可以用于数组:

Object[] objArray = new String[] { "Hello!" };
objArray[0] = new Object();
Run Code Online (Sandbox Code Playgroud)

由于数组类型系统在Java中的工作方式,此代码编译得很好.它会ArrayStoreException在运行时提高.

决定不允许对泛型的这种不安全行为.

另请参见其他地方:Java Arrays Break Type Safety,许多人认为它是Java Design Flaws之一.


Tho*_*thy 5

列表<动物>是一个对象,可以插入任何动物,例如猫或章鱼。一个的ArrayList <狗>是没有的。


Rev*_*nzo 5

你要做的是以下几点:

List<? extends Animal> animals = new ArrayList<Dog>()
Run Code Online (Sandbox Code Playgroud)

这应该工作.

  • 这对外行人解释了吗?我不这么认为. (6认同)