我看到这个问题已经被回答了很多次,只想在同一个问题上输入我的意见。
让我们继续创建一个简化的Animal类层次结构。
abstract class Animal {
void eat() {
System.out.println("animal eating");
}
}
class Dog extends Animal {
void bark() { }
}
class Cat extends Animal {
void meow() { }
}
现在让我们看看我们的老朋友Arrays,我们知道它隐式支持多态性-
class TestAnimals {
public static void main(String[] args) {
Animal[] animals = {new Dog(), new Cat(), new Dog()};
Dog[] dogs = {new Dog(), new Dog(), new Dog()};
takeAnimals(animals);
takeAnimals(dogs);
}
public void takeAnimals(Animal[] animals) {
for(Animal a : animals) {
System.out.println(a.eat());
}
}
}
该类编译良好,当我们运行上面的类时,我们得到输出
animal eating
animal eating
animal eating
animal eating
animal eating
animal eating
这里需要注意的是,takeAnimals()方法被定义为接受Animal类型的任何东西,它可以接受Animal类型的数组,也可以接受Dog类型的数组。这就是多态性的作用。
现在让我们对泛型使用相同的方法,
现在假设我们稍微调整一下代码,使用ArrayList而不是Arrays-
class TestAnimals {
public static void main(String[] args) {
ArrayList<Animal> animals = new ArrayList<Animal>();
animals.add(new Dog());
animals.add(new Cat());
animals.add(new Dog());
takeAnimals(animals);
}
public void takeAnimals(ArrayList<Animal> animals) {
for(Animal a : animals) {
System.out.println(a.eat());
}
}
}
上面的类将编译并生成输出-
animal eating
animal eating
animal eating
animal eating
animal eating
animal eating
所以我们知道这是可行的,现在让我们稍微调整一下这个类,使其以多态的方式使用Animal类型-
class TestAnimals {
public static void main(String[] args) {
ArrayList<Animal> animals = new ArrayList<Animal>();
animals.add(new Dog());
animals.add(new Cat());
animals.add(new Dog());
ArrayList<Dog> dogs = new ArrayList<Dog>();
takeAnimals(animals);
takeAnimals(dogs);
}
public void takeAnimals(ArrayList<Animal> animals) {
for(Animal a : animals) {
System.out.println(a.eat());
}
}
}
看起来编译上面的类应该没有问题,因为takeAnimals()方法被设计为接受Animal和Dog-is-Animal类型的任何ArrayList,因此它不应该成为交易破坏者。
但是,不幸的是,编译器抛出了一个错误,不允许我们将Dog ArrayList传递给期望Animal ArrayList的变量。
你问为什么?
因为想象一下,如果JAVA允许将Dog ArrayList-dogs-放入Animal ArrayList中-animals-然后在takeAnimals()方法中,有人会这样做-
animals.add(new Cat());
认为这应该是可行的,因为理想情况下它是一个Animal ArrayList,您应该能够将任何猫添加到其中,作为cat-is-also-Animal,但实际上您将一个Dog类型的ArrayList传递给了它。
所以,现在您必须想到,数组也应该发生同样的情况。你这样想是对的。
如果有人试图用Arrays做同样的事情,那么Arrays也会抛出一个错误,但Arrays在运行时处理这个错误,而ArrayList在编译时处理这个问题。