泛型和子类型 (Generics and Subtyping)
让我们来测试一下你对泛型的理解。下面的代码段合法吗?
List<String> ls = new ArrayList<String>(); // 1
List<Object> lo = ls; // 2
第1行当然是合法的。比较棘手的是第2行。这归结于一个问题:String List 是 Object List 吗?大多数人凭直觉回答:是!
再看看接下来的几行:
lo.add(new Object()); // 3
String s = ls.get(0); // 4: 尝试将Object分配给String!
这里我们别名化了 ls 和 lo 。通过别名 lo 访问 ls (一个 String List),我们可以向其中插入任意对象。因此 ls 不再只保存String,当我们试图从中得到一些东西时,我们会得到一个“惊喜”。
当然,Java编译器将防止这种情况发生。第2行将导致编译时错误。
通常,如果Foo是Bar的子类型(子类或子接口),而G是泛型类型声明,但 G<Foo> 却不是 G<Bar> 的子类型。这可能是你需要学习的关于泛型的最困难的事情,因为它违背了我们根深蒂固的直觉。
我们不应该假设集合不会改变。我们的本能可能导致我们认为这些事情是不可改变的。
例如,如果 车管所 向 人口普查局 提供一份司机名单,这似乎是合理的。我们认为 List<Driver> 是一个 List<Person> ,假设 Driver 是 Person 的子类型。事实上,被递交的应该是司机名单的副本,否则,人口普查局可能会在名单上增加新的非司机的人口记录从而破坏了车管所的记录。
为了应对这种情况,我们要考虑更灵活的泛型类型。到目前为止,我们所见到的规则是相当严格的。
本文译自:https://docs.oracle.com/javase/tutorial/extra/generics/subtype.html