为什么不能在Java中的<childinterface>类型的容器中存储类型为<parentinterface>的对象?

时间:2016-07-07 04:54:15

标签: java

我创建了一个界面:

MyList<E> extends List<E>{
...
}

但是,当我尝试执行:MyList<_MyClass> = new LinkedList<_MyClass>()时,出现编译错误。

如果MyList根据定义包含List中的所有方法,为什么我不能分配它? 如果我尝试强制转换它,我会得到一个运行时强制转换异常。

我错过了什么?

EDIT。感谢所有回复的人。我认为你可以将它与新的1.8默认方法一起使用,以便像C#扩展方法一样破解。即MyList有很多用于处理List的默认方法(没有其他方法),但我现在看到为什么这在概念上是不可能的。

3 个答案:

答案 0 :(得分:3)

从更简单的界面来考虑它。

假设核心库有一个Animal接口。 还有一个名为Dog的实现。也就是说,Dog实现了Animal。

现在你来创建一个名为Human的动物的新实现。

Human也实现了Animal。

所以现在我可以做到这一点。

Animal  a1, a2;
a1 = new Dog();
a2 = new Human();

但我不能这样做。

Human h = new Dog();

当然,人类和狗都是动物,但狗不可能代表人类。那是一个编译时例外。

现在你有一个稍微复杂的案例。

List是您的主界面,核心实现是LinkedList。也就是说,LinkedList实现了List。

因此扩展我的类比,你创建了一个名为HumanList的新类,它也扩展了List。

重复我以前做过的事,你可以做到这一点。

List<String>  b1, b2;

b1 = new LinkedList<String>;
b2 = new HumanList<String>;

但你不能这样做。

HumanList<String> = new LinkedList<String>.

当然,HumanList和LinkedList都是List的实现。但是LinkedList在所有情况下都不能代表HumanList。

这是因为除了List接口之外,您的HumanList实现还可以使用其他方法,例如displaySocialSecurityNumbers()。

如果您的HumanList除了List之外没有其他方法,并且您永远不需要它,那么您可以执行以下操作。

List<E>  b2 = new HumanList<E>();

最后,正如Xgord已经建议的那样,如果你想建议你的HumanList是一种LinkedList,那么你应该让HumanList扩展LinkedList。

答案 1 :(得分:2)

这是因为MyList个对象不是LinkedList类型的,这是您要分配的内容。

MyListLinkedList都扩展List,使其List类型对象。但是,通过分配MyList<_MyClass> = new LinkedList<_MyClass>(),您声明LinkedList对象是MyList对象,而实际情况并非如此。

将您的课程更改为:

MyList<E> extends LinkedList<E>{
...
}

它应该有用。

<强> 修改

刚刚意识到我也成了Is-A陷阱的受害者。如果您执行MyList<E> extends LinkedList<E>,那么您实际上需要将作业交换为:LinkedList<_MyClass> x = new MyList<_MyClass>()

答案 2 :(得分:1)

要添加@Teto所说的内容,它将会破坏Liskov Substitutuion Principle

  

可替代性是面向对象编程的一个原则   声明,在计算机程序中,如果S是T的子类型,那么   类型T的对象可以用类型S的对象替换(即,   类型T的对象可以用其子类型对象替换   类型S)而不改变任何所需的属性   程序(正确性,执行任务等)。

在您的情况下,MyList可能会添加一些不属于List的行为,因此不会成为LinkedList的一部分。 因此LinkedList无法取代MyList