1. 概述
在引入范型之前,Java类型分为原始类型、复杂类型,其中复杂类型分为数组和类。引入范型后,一个复杂类型就可以在细分成更多的类型。例如原先的类型List,现在在细分成List<Object>, List<String>等更多的类型。注意,现在List<Object>, List<String>是两种不同的类型,他们之间没有继承关系,即使String继承了Object。下面的代码是非法的
List<String> ls = new ArrayList<String>();
List<Object> lo = ls;
这样设计的原因在于,根据lo的声明,编译器允许你向lo中添加任意对象(例如Integer),但是此对象是List<String>,破坏了数据类型的完整性。
在引入范型之前,要在类中的方法支持多个数据类型,就需要对方法进行重载,在引入范型后,可以解决此问题(多态),更进一步可以定义多个参数以及返回值之间的关系。
例如
public void write(Integer i, Integer[] ia);
public void write(Double d, Double[] da);
的范型版本为
public <T> void write(T t, T[] ta);
2. 定义&使用
推荐的命名约定是使用大写的单个字母名称作为类型参数。这与 C++ 约定有所不同,并反映了大多数泛型类将具有少量类型参数的假定。对于常见的泛型模式,推荐的名称是:
K —— 键,比如映射的键。
V —— 值,比如 List 和 Set 的内容,或者 Map 中的值。
E —— 异常类。
T —— 泛型。
2.1 定义带类型参数的类
在定义带类型参数的类时,在紧跟类命之后的<>内,指定一个或多个类型参数的名字,同时也可以对类型参数的取值范围进行限定,多个类型参数之间用,号分隔。定义完类型参数后,可以在定义位置之后的类的几乎任意地方(静态块,静态属性,静态方法除外)使用类型参数, 就像使用普通的类型一样。注意,父类定义的类型参数不能被子类继承。
public class TestClassDefine<T, S extends T> {
....
}
2.2 定义带类型参数方法
在定义带类型参数的方法时,在紧跟可见范围修饰(例如public)之后的<>内,指定一个或多个类型参数的名字,同时也可以对类型参数的取值范围进行限定,多个类型参数之间用,号分隔。定义完类型参数后,可以在定义位置之后的方法的任意地方使用类型参数,就像使用普通的类型一样。
例如:
public <T, S extends T> T testGenericMethodDefine(T t, S s){
...
}
注意:定义带类型参数的方法,其主要目的是为了表达多个参数以及返回值之间的关系。例如本例子中T和S的继承关系, 返回值的类型和第一个类型参数的值相同。如果仅仅是想实现多态,请优先使用通配符解决。