1 泛型类
泛型类可以有多个类型变量,用尖括号(< >)括起来,并放在类名的后面。
通常用E表示集合的元素类型, K 和 V 分别表示表的关键字与值的类型。 T、U、S等表示“任意类型”。
泛型类可看作普通类的工厂。
public class Pair<T,U>{}
public class Pair<T>{
private T first;
public Pair(T first){ this.first=first;}
public T getFirst(){ return first;}
public void setFirst(T first){ this.first=first;}
}
2 泛型方法
泛型方法可以定义在普通类中,也可以定义在泛型类中。
只有声明了 <T>
的方法才是泛型方法
类型变量放在修饰符的后面,返回类型的前面。
class ArrayAlg{
public static <T> T getMiddle(T... a){
return a[a.length/2];
}
}
3 类型变量的限定
通过对类型变量 T 设置限定,对类型变量加以约束。
T 和绑定类型可以是类,也可以是接口。
<T extends Bounding Type >
一个类型变量或通配符可以有多个限定。
限定类型用“&”分隔,而逗号用来分隔类型变量。
<T extends Comparable & Serializable,U>
在 Java 的继承中,可以拥有多个接口超类型,但限定中至多有一个类。如果用一个类作为限定,它必须是限定列表中的第一个。
4 泛型代码和虚拟机
4.1 原始类型
虚拟机中没有泛型,泛型类型都会转换为相应普通类,即原始类型。
原始类型的名字就是删去类型参数后的泛型类型名。擦除类型变量,并替换为第一个限定类型(无限定的变量用Object)。
Pair<T>
的原始类型:
public class Pair{
private Object first;
public Pair(Object first){this.first=first;}
public Object getFirst(){ return first; }
public void setFirst(Object first){ this.first=first; }
}
4.2 类型转换
当程序调用泛型方法时,如果擦除返回类型,编译器插入强制类型转换。
- 调用原始方法
- 将返回的 Object 对象进行强制类型转换
当存取一个泛型域时也要插入强制类型转换。
4.3 桥方法
当泛型方法被擦除后与多态发生冲突,编译器会在泛型方法类中生成一个桥方法。
//超类
class Pair<T>{
public void setSecond(T second){}
}
//子类
class DateInterval extends Pair<Date>{
public void setSecond(Date second){}
}
//子类被擦除后
class DateInterval extends Pair{
public void setSecond(Date second){ ... }
}
//还有从超类继承的方法
public void setSecond(Object second)
//此时调用,多态冲突
DateInterval interval=new DateInterval(...);
Pair<Date> pair=interval;//OK--assignment to superclass
pair.setSecond(aDate);
//编译器在DateInterval类中生成桥方法
public void setSecond(Object second){ setSecond((Date) second); }
5 约束与局限性
- 类型参数不支持基本类型
- 运行时类型检查只适用于原始类型
instanceof、getClass 判断获取的都是原始类型 - 不能抛出或捕获泛型类的实例
可在异常声明中 - 不能创建参数化类型的数组
可以使用 ArrayList - 不能实例化类型变量
不能使用 new T(…), new T[…] 或 T.class 这样的表达式 - 泛型类的静态上下文中的类型变量无效
不能在静态域或方法中引用类型变量,要重新定义 - 注意擦除后的冲突
6 通配符类型
6.1 子类型限定
<? extends Class>
? extends Employee getFirst()
void setFirst(? extends Employee)
可以调用 get,不能调用 set 方法。
6.2 超类型限定
<? super Manager>
? super Manager getFirst()
void setFirst(? super Manager)
可以调用 set,不能调用 get 方法。
6.2 无限定通配符
<?>
? getFirst()
void setFirst(?)
get 的返回值只能赋给一个 Object,set 方法不能被调。