我正在阅读“Head First Java” - 非常酷的Java入门书。我有一个关于泛型的问题。
本书正确地指出,不可能将子类型多态地传递给接受ArrayList的方法。以下示例 -
public class Animal {
}
public class Dog extends Animal {
}
public class Cat extends Animal {
}
public class AnimalTester {
public static void main (String[] args) {
new AnimalTester().go();
}
public void go() {
List<Animal> animalList=new ArrayList<Animal>();
List<Dog> dogList=new ArrayList<Dog>();
processAnimals(animalList); // this would compile
processAnimals(dogList); // this would not compile
}
public void processAnimals(List<Animal> animalList) {
}
}
然而,上述内容可以通过使用泛型来解决 -
public <T extends Animal> void processAnimals(List<T> animalList) {
}
但是在上面的例子中,如果尝试将任何内容添加到列表中,编译器将抛出异常(这在本书中提到)。我尝试使用我的IDE,它确实引发了异常。该书还提到这是为了确保将不正确的对象(例如cat)添加到列表中(在我们的例子中为dogList)。
然而,我可以通过使用(T)投射猫/狗/动物对象来做到这一点。
public <T extends Animal> void processAnimals(List<T> animalList) {
animalList.add(new Animal()); // compilation Error
animalList.add(new Dog()); // compilation Error
animalList.add(new Cat()); // compilation Error
animalList.add((T) new Cat()); // works and I can also cast it back
// to Cat and get a Cat object
}
根据本书,Java创建者抛出异常的全部原因是因为不应将不正确的对象添加到列表中。然而,Java允许它,因为程序员明确地投射它并因此说“我知道我在做什么”?
答案 0 :(得分:3)
基本上,你在编译器上运行了一次。
你必须考虑泛型的全部观点。它们仅用于编译时安全。他们没别买你。在运行时,由于类型擦除,您仍然在处理List<Object>
,它可以容纳任何东西。如果您决定明确地投射某些内容,那么编译器将不会再猜测您。您已经将潜在的危险从编译时移到运行时,这是您的选择。