简单的泛型类
泛型程序设计意味着编写的代码可以被很多不同类型的对象所重用。
一个泛型类(generic class) 就是具有一个或者多个类型变量的类,且泛型类中可以有多个类型变量,类定义中的类型变量指定方法的返回类型以及域和局部变量的类型。
如:public class Pair\
{…} private T first;
在Java库中,使用变量E表示结合的元素类型,K和V分别表示表的关键字与值得类型,T(U,S) 表示任意类型。
泛型方法
定义泛型方法时,类型变量放在修饰符(如public,static等)的后面,返回类型的前面。
如:
12345class ArrayAlg{public static <T> T getMiddle(T... a){return a[a.length/2];}}泛型方法可以定义在普通类中,也可以定义在泛型类中,当调用一个泛型方法时,在方法名前的尖括号放入具体的类型也可以省略。
如: String middle= ArrayAlg.\
getMiddle(); 该调用中的
<String>
即可省略。
类型变量的限定
\
- 表示T应该是绑定类型(BoundingType)的子类型,T和绑定类型可以是类,也可以是接口。
- 限定类型用”&”分隔,类型变量用”,”分隔
- 在Java的继承中,可以根据需要拥有多个接口超类型,但限定至多只有一个类;如果用一个类作为限定,他必须是限定列表中的第一个。
泛型代码和虚拟机
- 虚拟机没有泛型类型对象,所有对象都属于普通类。
- 无论何时定义一个泛型类型,都自动提供了一个相应的原始类型。原始类型的名字就是删除类型参数后的泛型类型名。 擦除类型变量,并替换为限定类型(无限定用Object)。
- 类型擦除可能与多态发生冲突,可以利用桥方法来保持多态。
- 所有的类型参数都用他们的限定类型替换。
约束与局限性
类型参数不能使用基本类型,原因是类型擦除后,泛型类含有Object类型的域,而其不能存储基本类型(如double)的值。
所有的类型查询只产生原始类型
如:
1234Pair<String> stringPair=...;Pair<Employee> employeePair=...;if(StringPair.getClass()==employeePair.getClass())//they are equal,与类型变量无关不能创建参数化类型的数组,但是生命类型为Pair\
[]的变量仍为合法的,不过不能用new Pair\ [10]初始化。 如果需要手机参数化类型对象,唯一安全有效的方法时使用ArrayList:
ArrayList<Pair<String>>
不能构造一个泛型数组,如果数组仅仅作为一个类的私有实力域,就可以将这个数组声明为Object[],并且在获取元素时进行类型转换。P541
不能在静态域或者方法中引用类型变量
如:
123456789public class Singleton<T>{private static T singleInstance; //ERRORpublic static T getSingleInstance() //ERROR{if(ssingleInstance==null) construct new instance of Treturn singleInstance;}}类型擦除之后,T失效,只剩下Singleton类。
泛型类型的继承规则
- 无论S与T有什么联系,通常,Pair\
与Pair\没什么联系。 - 泛型类可以扩展或实现其他的泛型类。例如:ArrayList\
类实现了List\ 接口。
通配符类型
通配符的超类型限定(例)
? super Manager
这个通配符限制为Manager的所有超类型,带有超类型限定的通配符可以为方法提供参数,但不能使用返回值。
通配符的子类型限定(例)
? extends Employee
这个通配符限制为Employee的所有子类型,可以接受方法的返回值,但不能提供参数。即可以使用get()方法,但是无法使用set()方法。
带有超类型限定的通配符可以向泛型对象写入,带有子类型限定的通配符可以从泛型对象读取。
无限定通配符
Pair<?>
Pair<?>与Pair的本质不同在于:可以用任意Object对象调用原始的Pair类的setObject方法。