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. 定义&使用
类型参数的命名风格为:
推荐你用简练的名字作为形式类型参数的名字(如果可能,单个字符)。最好避免小写字母,这使它和其他的普通
的形式参数很容易被区分开来。
使用T代表类型,无论何时都没有比这更具体的类型来区分它。这经常见于泛型方法。如果有多个类型参数,我们
可能使用字母表中T的临近的字母,比如S。
如果一个泛型函数在一个泛型类里面出现,最好避免在方法的类型参数和类的类型参数中使用同样的名字来避免混
淆。对内部类也是同样。
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的继
承关系, 返回值的类型和第一个类型参数的值相同。
如果仅仅是想实现多态,请优先使用通配符解决。通配符的内容见下面章节。
public <T> void testGenericMethodDefine2(List<T> s){
...
}
应改为
public void testGenericMethodDefine2(List<?> s){
...
}
3. 类型参数赋值
当对类或方法的类型参数进行赋值时,要求对所有的类型参数进行赋值。否则,将得到一个编译错误。
3.1 对带类型参数的类进行类型参数赋值
对带类型参数的类进行类型参数赋值有两种方式
第一声明类变量或者实例化时。例如
List<String> list;
list = new ArrayList<String>;
第二继承类或者实现接口时。例如
public class MyList<E> extends ArrayList<E> implements List<E> {...}
3.2 对带类型参数方法进行赋值
当调用范型方法时,编译器自动对类型参数进行赋值,当不能成功赋值时报编译错误。例如
public <T> T testGenericMethodDefine3(T t, List<T> list){
...
}
public <T> T testGenericMethodDefine4(List<T> list1, List<T> list2){
...
}
Number n = null;
Integer i = null;
Object o = null;
testGenericMethodDefine(n, i);//此时T为Number, S为Integer
testGenericMethodDefine(o, i);//T为Object, S为Integer
List<Number> list1 = null;
testGenericMethodDefine3(i, list1)//此时T为Number
List<Integer> list2 = null;
testGenericMethodDefine4(list1, list2)//编译报错
|
|