这些Java教程是针对JDK 8编写的。本页中描述的示例和实践不利用后续版本中引入的改进,并且可能使用不再可用的技术。
有关Java SE 9及后续版本中更新的语言功能的摘要,请参阅Java语言更改。
有关所有JDK版本的新功能、增强功能以及已删除或不推荐选项的信息,请参阅JDK发行说明。
让我们来测试一下你对泛型的理解。下面的代码片段是否合法?
List<String> ls = new ArrayList<String>(); // 1 List<Object> lo = ls; // 2
第1行显然是合法的。问题比较棘手的部分是第2行。这归结为一个问题:一个List
的String
是否是List
的Object
。大多数人本能地回答:“当然可以!”
好吧,看看接下来的几行:
lo.add(new Object()); // 3 String s = ls.get(0); // 4:尝试将一个Object赋值给String!
我们给ls
和lo
起了别名。通过别名lo
访问ls
(一个String
的列表),我们可以将任意对象插入其中。结果ls
不再仅仅包含String
,当我们尝试从中获取一些内容时,会有一个不礼貌的惊喜。
当然,Java编译器会防止这种情况发生。第2行会导致编译时错误。
通常情况下,如果Foo
是Bar
的子类型(子类或子接口),而G
是某个泛型类型声明,则G<Foo>
不是G<Bar>
的子类型。这可能是你需要了解的泛型中最困难的事情,因为它与我们深深扎根的直觉相悖。
我们不应该假设集合不会发生变化。我们的直觉可能让我们认为这些东西是不可变的。
例如,如果车辆管理部门向人口普查局提供司机列表,这似乎是合理的。我们认为List<Driver>
是List<Person>
,假设Driver
是Person
的子类型。实际上,传递的是驾驶员登记表的一个副本。否则,人口普查局可能会向列表中添加不是驾驶员的新人,破坏车辆管理部门的记录。
为了应对这种情况,考虑更灵活的泛型类型是很有用的。到目前为止,我们所见到的规则相当严格。