# 泛型和子类型化

以下代码合法吗?

List<String> ls = new ArrayList<String>(); // 1
List<Object> lo = ls; // 2 
1
2

第一行是合法的,对于第二行,大多数人的本能反应是可以的。继续看看下面的代码

lo.add(new Object()); // 3
String s = ls.get(0); // 4: 尝试将 Object 赋值给字符串
1
2

这里通过 lo 访问 ls,也就是说,第三行:ls 里面被添加进了一个 Object 对象,第 4 行,将 Object 对象赋值给 String 对象。通过 lo 可以插入任意对象,结果已经不再是 String 了。

所以 Java 编译器防止这种情况的产生,第 2 行将导致编译时错误。

通常,如 Foo 是 Bar 的子类,并且 G 是一个泛型类型声明,G <Foo> 并非是 G <Bar> 的子类型。这可能是你学习泛型最困难的事情,因为他违背了我们一贯的直觉。

有一个例子可以帮助你来理解:

  • Driver 驾驶员是 Person 人类的子类
  • List<Driver> 如果是等同于 List<Person>

那么:不是驾驶员的人员可能被添加到列表中,这是很危险的事情;不会开车的人成为了驾驶人员。

为了应对这种情况,考虑更灵活的泛型类型很有用。到目前为止,我们看到的规则非常严格。