Java集合中泛型指的是在创建集合的时候要同时指定集合中存放的对象类型,这样做主要是基于类型安全方面的考虑。
比如假设我们要创建一个用于存放字符串的ArrayList,我们通常使用如下的方式:
ArrayList<String> list = new ArrayList<String>();
注意尖括号及其里面的内容,这样我们的这个 list 中就只能存放 String 类型的对象,当我们试图向这个 list 中添加非 String 类型的对象(引用)的时候,会编译不通过,提示“找不到符号”(我觉得提示“找不到方法”更准确)。原因就是我们已经声明 ArrayList 中存放的 String 类型,当我们向这个 ArrayList 中添加对象(引用)的时候,编译器就会检查你存放的是否是 String 类型,如果不是,便会编译不通过,这就是所谓的类型安全问题。
在数组中存放对象(引用)的时候,编译器也会进行检查,当添加其他类型的对象的时候,编译不会通过,提示“不兼容的类型”。
上面介绍的是集合中的泛型问题,下面看一下集合中的多态问题,这才是本文的核心所在。
我们知道Java中的多态指的是:在程序中定义的某个引用变量具体所指向的类型和调用的方法在编码时并不能确定,而只有在运行的时候才能确定。简单来说就是这样的情况:你定义的引用变量是父类型,而你创建的对象是子类型,用这个父类型的引用变量指向这个子类型的对象,然后当你调用这个对象的方法的时候,具体是调用的父类的还是子类的方法只有在运行的时候才能确定,可能调用的是父类的方法也有可能调用的子类的方法,这样不用修改代码,就可以让成徐选择多个运行的状态,这就是多态。(关于多态,不明白的去查书。)
关于多态,简单理解就是适合父类的,必定也适合子类,即父类存在的地方也可以用子类来替换(而这其实对应一种设计原则,你也知道是吧,对,就是里氏替换原则。这里不介绍这个原则哈,只是顺便提一下。)
基于此,我们考虑集合中多态的情况。
先假设有一个方法如下(Animal为某类,Dog是其一个子类):
public void method(Animal anim){}
根据多态,我们知道我们可以用子类替换父类,而 Dog 是 Animal 的子类即我们可以用一个 Dog 类型的对象作为该方法的参数,这没问题吧。是没问题的,我们继续。
我们引入集合及泛型,假设有某方法如下:
public void method(ArrayList<Animal> anim){}
则按照多态,理论上我们可以传递如下参数:一个 ArrayList<Dog> 类型的对象( Dog 为 Animal 的子类),理论上没问题吧,而实际上却是大有问题的,会编译不通过。
这是为什么呢?Dog为Animal的子类,父类存在的地方,子类就可以存在,这应该是没错的啊,这确实是没有错的,错不在多态。我们可以反向思考一下,假设允许上面的情况发生,就是在需要一个ArrayList<Animal>对象的地方你传入了ArrayList<Dog>对象,但接下来发生的情况是否会发生你就无法预料了,就是你在method中调用了anim.add(new Cat()),这是可以理解的吧(假设Cat是Animal的另一子类),因为方法的参数类型是ArrayList<Animal>类型的,即这个ArrayList中存放的是Animal,Cat是Animal的子类所以可以调用anim.add(new Cat()),但事实上你传递的确实ArrayList<Dog>类型的,即你向一个存放Dog的ArrayList中存放了其他的对象,根据泛型安全性问题,这是不允许的啊。所以假设不成立,即你不能向一个参数类型为ArrayList<Animal>的方法中传递ArrayList<Dog>类型的对象。(真TM的像用反证法证数学题啊,有木有啊!)
晕了没,希望你没有。