如果是数组,我们可以说Animal[] animals = new Cat[10];
但是,使用通用语法我们不能说List<Animal> is a
ArrayList<Cat>
。
List<Animal>
可以引用任何只有Animal和的多态基集合
没有别的,为了类型安全。
public void foo() {
Cat[] cats = {new Cat(), new Cat()};
addAnimals(cats);
}
public void addAnimal(Animal[] animals) {
animals[0] = new Dog(); // No compile time error. But ArrayStoreException
// at runtime as the JVM knows the type of animals.
}
如果泛型是隐式多态的,在最坏的情况下,即使我们在集合中添加了一些错误的元素并做了类似于上面代码中的一些东西,最多我们会得到一个ClassCastException
(或其他一些例外)也会阻止像ArrayStoreException
这样的程序流吗?
我已经读过,对于泛型,由于类型擦除,JVM对集合的类型一无所知,因此它不会抛出像ArrayStoreException
这样的异常。
我的问题是为什么在typed
集合的情况下这么多的编译时间保护?为什么有这么多挑剔的规则与泛型?请提供正确的理解。
答案 0 :(得分:1)
一种常见的误解是,泛型被引入作为现有Java多态的扩展。这不是真的。引入Java泛型以允许编译时间类型检查。
interface Species {
}
class Animal implements Species {
}
class Cat extends Animal {
}
class Dog extends Animal {
}
class Plant implements Species {
}
class Tree extends Plant {
}
public void test() {
System.out.println("Hello");
List<Animal> animals = new ArrayList<>();
animals.add(new Cat());
animals.add(new Dog());
// Not allowed.
//animals.add(new Tree());
// The old way.
List beasts = new ArrayList();
beasts.add(new Cat());
beasts.add(new Dog());
// Allowed - only caught at run time and difficult to find.
beasts.add(new Tree());
// The interface way.
List<Species> living = new ArrayList();
living.add(new Cat());
living.add(new Dog());
// Allowed.
living.add(new Tree());
}
泛型的目的是简单地指定对象可以处理的类,并在编译时检查它。
泛型也使接口的使用更加整洁。
答案 1 :(得分:0)
这个想法是泛型的目的是类型安全。如果List<Cat>
是List<Animal>
的子类 - 它会违反它:
List<Cat> cats = new ArrayList<Cat>();
List<Animal> animals = cats;
animals.add(new Dog());
上面的编译会很好 - 但是当你尝试访问cats
时会发生什么?它将有一个不是Cat
的元素,例如:
for (Cat c : cats) { ...}
会失败。