概念
泛型,即“参数化类型”,在java中是指把类型明确的工作推迟到创建对象或调用方法的时候再去做。
一个例子
1 | List arrayList = new ArrayList(); |
运行上面的代码将抛出异常:java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
。
ArrayList作为一个容器,可以存放任意类型(Object类型),例子中添加了一个String类型,添加了一个Integer类型,但使用时都当做String类型来使用,所以报错。从这个例子可以看到,因为开发人员可以把多个类型放入容器,从容器中取出时需要转换成实际的类型,但开发人员很难知道容器中所有的元素的实际类型是什么,所以就会导致类型不安全的问题。而泛型的引入,可以让程序在编译阶段就杜绝这种类型安全问题。
将例子中的第一行声明初始化list的代码更改一下,看看会有什么样的结果:
1 | List<String> arrayList = new ArrayList<String>(); |
可以看到使用泛型后编译器就能帮助我们做类型安全的检查工作,这就避免了取出元素时可能发生的ClassCastException异常,开发人员无需记住各个对象的类型并担心类型的匹配问题,因为里面的元素都是ArrayList声明的泛型类型,取出时也无需再做强制类型转换。
泛型的使用
泛型有三种使用方式,分别为:泛型类、泛型接口、泛型方法。
泛型类
泛型类型用于类的定义中,被称为泛型类。通过泛型可以对一种类型对外开放相同的操作,最典型的就是各种容器类,如:List、Set、Map,可以完成各种增删改查操作。
泛型类定义的简单示例:
1 | //此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型 |
使用这个泛型:
1 | //泛型的类型参数只能是类类型(包括自定义类),不能是简单类型 |
注意:泛型的类型参数只能是类类型,不能是简单类型。
此外,泛型的<>
里也可以放多个参数:
1 | public class Generic<T,S> { |
泛型接口
泛型接口与泛型类的定义及使用基本相同。在实现(或继承)泛型接口(或类)时,可以明确泛型接口(或类)的类型,也可以不明确。
定义一个泛型接口:
1 | public interface Generator<T> { |
明确类型
在实现泛型类时明确父类的类型:
1 | public class FruitGenerator implements Generator<String> { |
不明确类型
1 | class FruitGenerator<T> implements Generator<T>{ |
泛型方法
泛型方法的一个特征是在方法声明中,带有一对尖括号<>
。
1 | class GenerateTest<T>{ |
静态泛型方法
如果要在类中的静态方法使用泛型,须注意:①静态方法无法访问类上定义的泛型;②如果静态方法操作的引用数据类型不确定的时候,必须要将泛型定义在方法上。
即:如果静态方法要使用泛型的话,必须将静态方法也定义成泛型方法。
1 | public class StaticGenerator<T> { |
泛型通配符
看看这个泛型和多态的问题,Dog,Cat是Animal的子类:
1 | public void feddAll(ArrayList<Animal> animals) { |
这个例子中需要使用泛型通配符来解决,将feddAll()方法改成如下,编译就可以通过了。
1 | public void feddAll(ArrayList<T extends Animal> animals) { |
泛型的通配符包括了如下几种。
无界:?
“?”可以用来接收任何类型,例子如下:
1 | public void processElements(List<?> elements){ |
上界:? extends A
表示泛型可以接收任何A类或A类的子类。
1 | public void processElements(List<? extends A> elements){ |
下界:? super A
表示泛型可以接收任何A类或A类的超类。
1 | public static void insertElements(List<? super A> list){ |
几个注意点
- 上界通配符主要用于读数据,下界通配符主要用于写数据。
?
和T
的区别。1
2
3
4
5//指定集合元素只能是T类型
List<T> list1 = new ArrayList<T>();
//集合元素可以是任意类型,基本上不会这么用,因为没有什么意义,这里只是说明用法。
List<?> list2 = new ArrayList<?>();
v1.5.2