1.为什么要使用泛型程序设计?
最初的类只能持有单个对象,这个类可以明确指定该类持有的对象类型。
class Automobile{}
public class Holder1{
private Automobile a;
public Holder1(Automobile a){this.a = a;}
public Automobile get(){
return this.a;
}
}
但该类的可重用性较差,当需要持有另外的对象时只能利用java的多态特性,编写不同传参对象的同名方法:
Class Automobile{}
Class Bycicle{}
public class Holder1{
private Automobile a;
private Bycicle b;
public Holder1(Automobile a){this.a = a;}
public Holder1(Bycicle B){this.b = b;}
public Automobile get(){
return this.a;
}
}
或直接让类持有Object对象
class Automobile{}
class Bycicle{}
public class Holder1{
private Object a;
public Holder1(Object a){this.a = a;}
public Object get(){
return this.a;
}
}
然而通常我们只期望持有一种类型的对象,而不是所有类型的对象。且使用object类型通常会容易发生强制装换错误,不能使用特定对象的方法。
2.泛型的用法
-
泛型类
泛型类引入了一个类型变量T,用尖括号<>括起来,并放在类名后面
//泛型类的定义
public class 类名<T>{...}
泛型类可以有多个类型变量
//泛型类的定义
public class 类名<T,U>{...}
-
泛型方法
泛型方法可以可以定义在普通类中,也可以定义在泛型类中。下述例子即是在普通类中定义的泛型方法。
//泛型方法的定义
public class ArrayAlg{
public statis <T> T getMiddle(T... a){
return a[a.length/2];
}
}
当调用一个泛型方法时,在方法名前的尖括号中放入具体的类:
//泛型方法的调用
String middle = ArrayAlg.<String>getMiddle("John","Snow","Aya")
通常不需要在方法名前添加尖括号,编译器就可以根据传入参数String[]类型与泛型类型T[]匹配并推断得出返回类型一定是String,以下写法也没有问题:
//泛型方法的调用
String middle = ArrayAlg.getMiddle("John","Snow","Aya")
-
类参数变量与方法参数变量的匹配
类似泛型方法的传入参数与返回类型之间的匹,泛型类与泛型方法之前也存在这种匹配限定。
//泛型方法的调用
public class Pair<T>{
private T first;
private T second;
public Pair(){first = null ;second = null;}
public Pair(T first ,T second){this.first = first; this.second = second;}
public T getFirst(){return this.first;}
public T getSecond(){return this.second;}
public void setFirst(T first){this.first = first;}
public void set Second(T second){this.second = second}
}
public static void main(String[] args){
Manager manager1 = new Manager("John");
Employee employee1 = new Employee("Lee");
Pair<Manager> manager = new Pair<Manager>(manager1,employee1 );//error
}
以上示例中已经实例化为Manager参数变量的Pair类,无法传入Employee参数变量。
3.类型变量的限定
有时,类或方法需要对类型变量加以约束。如:
//泛型方法的调用
public class ArrayAlg{
public static <T> T min(T[] a){
if(a == null || a.length == 0 ) return null;
T smallest = a[0];
for(int i = 1;i<a.length;i++){
if (smallest.compareTo(a[i]) > 0) smallest = a[i];
}
return smallest ;
}
}
上述例子中smallest类型为T,意味着T可以为任意变量,怎么确定T所属类有compareTo方法呢?可以通过对类型变量T设置限定实现这一点。
public static <T extends Comparable> T min(T[] a)
4.类型擦除
虚拟机没有泛型类型对象,所有类都属于普通类。
通过对泛型类提供一个原始类型(山区类型参数后的泛型类型名),擦除类型变量。
T为无限定的变量时,使用Object进行替换
T为限定的变量时,使用第一个限定的类型变量进行替换
类型擦除可能产生的冲突和泛型的局限性待补充
5.泛型类型的继承规则
上述图例中,ArrayList是List的子类,Manage是Employee类的子类,而List<Manager>是ArrayList<Manager>的子类。但List<Manage>并不是List<Employee>的子类,ArrayList<Manage>也不是ArrayList<Employee>的子类。
6.通配符
- 通配符子类型限定
//类型参数为Employee类的子类的限定
Pair<? extends Employee>
- 通配符超类型限定
//类型参数为Employee类的超类的限定
Pair<? super Employee>
- 无限定通配符
//无限定通配符
Pair<?>