为什么List <String>不是List <Object>的子类型?

n_x*_*x_l 4 java

可能重复:
java泛型协方差

我试图做的事实,感觉 List<String>不是一个亚型List<Object>.

在有效的Java中,Josh Bloch指出,虽然它看似违反直觉,但它确实有意义.他说的原因是你可以放入任何Object List<Object>,但只能放入String List<String>.我不确定这是如何证明String列表不是Object列表的子类型的原因.

也许我对这个词感到困惑subtype.我认为这意味着当S是T的子类型时,S的实例是T的实例.因此,List<String>要成为子类型List<Object>,Object必须是String的超类,从技术上讲它是.知道我的推理出错了吗?

pho*_*ser 11

List<String> s = new ArrayList<String>();
List<Object> o = s;
o.add(new Object());
String first = s.get(0);  // boom
Run Code Online (Sandbox Code Playgroud)

  • 评论为+1.大声笑! (2认同)
  • 里氏替换原则:如果“A”是“B”的子类型,那么您应该能够在可以使用“B”的任何地方使用“A”。这表明您不能在可以使用 ArrayList&lt;Object&gt; 的任何地方使用 ArrayList&lt;String&gt;`。 (2认同)

Dan*_*tin 5

这可以追溯到A成为B. 它的正式名称是Liskov 替换原则,它基本上说这A是一个子类型,B当且仅当您可以采用任何包含某种类型的有效程序B,交换某种类型A,它仍然是一个有效程序。 . 这样做的结果是,如果您可以在A任何可以使用 a的地方使用 an B,那么A是 的子类型B

所以在这种情况下,因为这是一个有效(有效的意思是“编译”)程序的一部分:

public static void doThing(List<Object> x) {
  x.add(new Object());
}
Run Code Online (Sandbox Code Playgroud)

然后,根据 Liskov 替换原则,如果List<String>List<Object>this 的一个子类型也将是有效程序的一部分:

public static void doThing(List<String> y) {
  y.add(new Object());
}
Run Code Online (Sandbox Code Playgroud)

但显然第二个片段无法编译。因此,第二个片段不是有效程序的一部分,因此List<String>不是List<Object>.

同样,反过来也不成立:List<Object>不是 的子类型List<String>。找到程序片段来证明这一点,留给读者作为练习。