让我们测试一下您对泛型的理解。以下代码段合法吗?

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

    第1行当然是合法的。这个问题的棘手的部分是第2行。这可以归结为一个问题:String类型的List可以是一个Object类型的List?大多数人本能地回答:“可以!”
    好吧,请看以下几行:

    1. lo.add(new Object()); // 3
    2. String s = ls.get(0); // 4: Attempts to assign an Object to a String!

    在这里,我们对lslo进行了别名。 通过别名lo访问ls(一个String列表),我们可以在其中插入任意对象。 结果ls不再只容纳String了,当我们尝试从中获取一些东西时,我们会感到困惑。
    Java编译器当然可以防止这种情况的发生。第2行将导致编译时错误。
    通常,如果FooBar的子类型(子类或子接口),并且G是某种泛型类型声明,则G<Foo>不是G<Bar>的子类型的情况。这可能是您需要学习泛型的最困难的事情,因为它违背了我们一贯的直觉。
    我们不应该假设集合不会改变。我们的本能可能使我们认为这些事情是不变的。
    例如,如果机动车部门向普查局提供了驾驶员名单,这似乎是合理的。我们认为List<Driver>List<Person>,假设DriverPerson的子类型。实际上,正在传递的是驾驶员注册表的副本。否则,人口普查局可能将不是驾驶员的新人添加到列表中,从而破坏DMV的记录。
    为了应对这种情况,考虑更灵活的泛型类型很有用。到目前为止,我们看到的规则非常严格。