目录
泛型程序设计意味着编写的代码可以对不同类型的对象进行重用
定义简单泛型类
类型变量和类型参数
//<T><U><S> 类型变量 ArrayList<String> files = new ArrayList<>();
E:集合的元素类型
K和V:键和值的类型
T、U、S:任意类型
Pair
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 class Pair<T,U>
{
T first;
U second;
public Pair(T first, U second) {
this.first = first;
this.second = second;
}
}
ArrayAlg
public class ArrayAlg
{
/**
* 从一组T类型的数据中获取最大值和最小值
* @param t T类型的数组
* @return Pair<T> 返回一对最大值和最小值。如果t为null或为空,则返回null
* <T extends Comparable> 是对T类型的一个限定,限制T只能是实现了Comparable的类。如果不设置限定,则写为<T>
*/
public static <T extends Comparable> Pair<T> minmax(T[] t)
{
if(t == null || t.length == 0) return null;
T min,max;
min = max = t[0];
for (int i = 0; i < t.length; i++) {
if (t[i].compareTo(min) < 0)
min = t[i];
if (t[i].compareTo(max) > 0)
max = t[i];
}
return new Pair<>(min ,max);
}
/**
* 泛型方法,返回泛型重载参数的中间那个参数
* <T>是声明,T是返回值 重载参数本质上是参数数组
*/
public static <T> T middle(T... args)
{
return args[args.length/2];
}
}
泛型代码和虚拟机
类型擦除(erasure)
定义泛型类型时,编译器会提供一个原始类型(raw type),名字就是去掉类型参数后的泛型类型名。
类型变量会被擦除(erased),并被替换为限定类型,或对于无限定的,则替换为Object。
泛型转换
-
虚拟机中没有泛型,只有普通类和方法
-
所有参数类型都会替换为它们的限定类型
-
会合成桥方法保持多态
-
为保持类型安全性,必要时会插入强制类型转换
泛型的限制与局限性
-
不能用基本类型去实例化
Pair<double>; //Error Pair<Double>; //Correct
-
运行时类型查询只适用于原始类型(即泛型类)
-
不能创建参数化类型数组
Pair<String> str = new Pair<>[10]; //Error
-
Varargs警告(可变参数警告)
-
不能直接实例化类型变量
public Pair() { first = new T(); second = new T();}//Error
-
不能构造泛型数组
类型擦出机制总会使构造方法构造限定类型数组或Object数组
-
不能在静态字段和方法中定义和引用类型变量
-
不能抛出或捕获泛型类的实例
-
可以取消对检查型异常的检查
泛型类型继承规则
无论T与S有什么关系,genericity<T>与genericity<S>都没有任何关系。想要在泛型程序中利用继承关系,则须引入通配符类型
通配符类型(wildcard type)
public static boolean hasNulls(Pair<?> pair){} //使用了无限定通配符?,不需要标注泛型方法
public class Employee{}
public class Manager extends Employee {}
//这里?没法改为T
public static void printBuddies(Pair<? extends Employee> pair){} //pair有2种类型选择:Employee or Manager
//超类型限定
public static void minmaxBonus(Manager[] managers, Pair<? super Manager> pair) //pair有3种类型选择:Object、Employee or Manager
//?不是类型变量
public static void swapHelper(Pair<?> pair)
{
? t = pair.getFirst(); //ERROR
pair.setFirst(pair.getSecond());
pair.setSecond(t);
}