Java泛型的逐步理解
理清泛型之前,先引入容器的概念。
容器:就是字面意思,存放东西用。而在java里容器类就是专门存放数据的类,例如集合ArrayList等等。集合这类容器都可以存放多个数据,我们也可以构建一个只存放单个元素的简单容器。
再利用数组实现存放多个数据的简单容器:
实现了存放数据后,发现只能存放固定的String类型数据,要实现存放任意类型怎么处理?
利用Object么?尝试一下:
由上,为了在创建容器对象时,指定任意且唯一一种类型的数据存入,这就是泛型应该要实现的效果。
泛型就是把类型明确的工作 推迟到创建对象或调用方法的时候才去明确 的特殊类型.
具体了解泛型的使用前,先给个参照:
方法和形参,就是设定了传入实参的数据类型,明确方法实参只能依照形参类型传入。
形参和实参,就是方法定义时,不用指定明确的参数,只相当于一个公式中的变量,使用方法的时候,再传入具体的实参。
同理,容器和泛型,也是对容器存入元素的引用类型设定,明确容器中元素只能存入该引用类型。区别就是,方法的形参类型在其定义时就已经明确,而泛型的类型需要创建对象时才明确。
同时,泛型又是引用类型的形参,即明确的具体类型就是引用类型的实参。
例如ArrayList{}
当创建对象时才明确类型ArrayList list = new ArrayList<>();即传入引用类型的实参String后,此容器内将只能存储String类型元素。
还是依照上面的例子:
我们知道引用类型即具体某一个类,String、ArrayList等等,引用类型数据都是对应类的实例对象引用;在创建容器对象时我们要指定泛型具体的引用类型,例如ArrayList list
那么,当我们在构建ArrayList等容器类时,它的泛型如何指定呢,为什么一般会用T?
我们构建泛型容器,是为了存入任意且唯一引用类型的数据,所以这时的泛型设定肯定要能代表所有引用类型。而上面已经提到过,构建容器时的泛型只是相当于一个形参,它没有具体意义,所以可以T,可以E等等。一般泛型设计使用E、T、K、V (E:element T: type K: key V: value)
泛型容器类的使用大家应该比较清楚了,那么方法的泛型有什么区别么?
泛型类和泛型方法的定义已经比较清楚了,但是如果在创建对象或者调用泛型方法时无法明确类型, 就需要使用泛型通配符 ?
?extends 父类 上限
?super 子类 下限
只需要注意一点,泛型通配符是在创建对象和调用方法时使用,而在定义泛型类和定义泛型方法时不能使用。
public void run(ArrayList<?> list) //这种普通方法定义形参,形参可以使用泛型,实际上是创建的ArrayList对象无法明确类型使用通配符,而不是定义的泛型方法中使用通配符
public <?> void add(? s){} // 报错
public <Container<?>> void add(Container<?> cup) //报错
一系列尝试后,创建对象时可以直接使用通配符,定义方法时,使用通配符的一般是作为形参的容器对象。