普通数组的工作方式
如下面的代码,函数takeAnimals的参数类型是Animal[[],在调用的时候,可以把Animal[]或者Dog[]传递进去( Dog是Animal的派生类)
import java.util.*;
public class TestGenerics1 {
public static void main( String[] args ) {
new TestGenerics1().go();
}
public void go() {
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 ) {
a.eat();
}
}
}
泛型的工作方式
我们把上例的Array替换为ArrayList
public void go() {
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 ) {
a.eat();
}
}
如上,takeAnimals传入ArrayList<Animal>是可以正常编译运行,没有问题的;但是如果仿照Array的例子,我们可以将ArrayList<Dog>传入takeAnimals吗?
ArrayList<Dog> dogs = new ArrayList<Dog>();
dogs.add( new Dog() );
dogs.add( new Dog() );
dogs.add( new Dog() );
takeAnimals( dogs );
上面这段code会compile error。
如果可以会怎样?
public void takeAnimals( ArrayList<Animal> animals ) {
animals.add( new Cat() );
}
如果ArrayList<Dog>可以传递给takeAnimals,那会出现Cat混入Dog集合的情形。
原因
数组的类型是在运行期间检查的,但集合的类型检查只会发生在编译期间
解决办法
public void takeAnimals( ArrayList<? extends Animal> animals ) {
for( Animal a: animals ) {
a.eat();
}
}
在使用带有<?>的声明时,编译器不会让你往集合中加入任何东西,只能读取。
另外一种相同功能的语法
public <T extends Animal> void takeAnimals( ArrayList<T> animals );
为什么要用这种形式?
如果要多次使用,会更有效率
public <T extends Animal> void takeThing< ArrayList<T> one, ArrayList<T> two )
// 而不必像下面这样
public void takeThing< ArrayList<? extends Animal> one, ArrayList<? extends Animal> two )
泛型与数组的区别
本文通过对比普通数组和泛型ArrayList在Java中的使用方式,详细解释了为什么泛型集合不能像数组那样接受其子类型的实例,并提出了解决方案。
1932

被折叠的 条评论
为什么被折叠?



