java chapter 8 泛型编程
class ArrayAlg{
public static <T> T getMiddle(T... a){
return a[a.length/2];
}
}
String middle=ArrayAlg.<String>getMiddle("John","q","Public");
限定泛型
public static <T extends Comparable> T min(T[] a)
T extends Comparable & Serializable
8.6.2 运行时类型仅仅在未加工类型中工作
if(a instanceof Pair
只能检测a是否是任意类型的Pair
if(a instanceof Pair
Pair<String> stringpair=...;
Pair<Employee> employeePair=...;
if(stringPair.getClass()==employeePair.getClass()//相等
getClass方法始终返回未加工类型。
8.6.3
你不能实例化参数化类型的数组
var table=new Pair<String>[10];//ERROR
不能实例化的原因是擦除后,table的类型是Pair[],你可以转换为Object
Object[] objarray=table;
objarray[0]="Hello";//ERROR 类型是Pair
8.6.4 Varargs警告
Java不支持泛型类的数组
8.6.5 你不能实例化类型变量
你不能使用new T(...) 下列代码是非法的
public Pair(){first=new T();second =new T();}//ERROR
JAVA 8后,你可以提供一个构造函数
Pair<String> p=Pair.makePair(String::new);
public static<T> Pair<T> makePair(Supplier<T> constr){
return new Pair<>(constr.get(),constr.get());
}
更传统的做法是使用反射.
不幸的是,这有一些复杂。你不能直接使用:
first=T.class.getConstructor().newInstance();//ERROR
你可以使用
public static <T> Pair<T> makePair(Class<T> cl){
try{
return new Pair<>(cl.getConstructor().newInstance(),cl.getConstructor().newInstance());
}
catch(Exception e){return null;}
}
Pair<String> p=Pair.makePair(String::class);
8.6.6 你不能构造泛型数组
数组会被填充Null值。这是为了构造的安全。但数组也有类型,虚拟机会用来监测数组存储。而它的类型是被擦去的。例
public static <T extends Comparable> T[] minmax(T...a){
T[] mm=new T[2];//ERROR
}
类型擦去会导致你构造了一个数组Comparable[2]
如果数组只被用于一个类的私有实例中,你可以使用类型转换
public class ArrayList<E>{
private Object[] elements;
@SuppressWarnings("unchecked")
public E get(int n){
return (E) elements[n];
}
public void set(int n,E e){
elements[n]=e;//no cast needed
}
}
上面最大值最小值的错误实例我们可以添加一个数组的构造函数
String[] names=ArrayAlg.minmax(String[]::new ,"Tom","Dick","Harry);
public static <T extends Comparable> T[] minmax(IntFunction<T[]>constr,T...a){
T[] result=constr.apply(2);
...
}
8.6.7类型变量在泛型类中不允许使用静态上下文
你不能引用静态变量和方法
public class Singleton<T>{
private static T singleInstance;//ERROR
public static T getSingleInstance(){//Error
if(singleInstance==null)construct new instance of T
return singleInstance;
}
}
8.6.8 你不能抛出或捕获泛型类的异常
泛型类不能抛出或捕获异常,甚至不能继承Throwable
public class Problem
你也不能使用类型变量在catch语句中。
public static <T extends Throwable> void doWork(Class<T> t){
try{
do work
}
catch(T e){//ERROR can't catch type variable
Logger.global.info(...);
}
}
但是你可以正常使用类型变量在异常中,下述代码合法
public static <T extends Throwable> void doWork(T t) throws T
{
try{
do work
}
catch(Throwable realCause){
t.initCause(realCause);
throw t;
}
}
8.6.9 你不能打败检验异常的检验
8.7泛型的继承规则
Pair
答案是否定的,
Pair
一般来言,Pair 与Pair
泛型类可以扩展或者实现其他泛型类。ArrayList
但ArrayList
8.8 通配符类型
8.8.1通配符概念
通配符类型,参数类型可以改变
Pair<? extends Employee>
标记任何Pair类型的泛型,都必须是Employee的子类。如Pair
你想要打印Employee的Pair值,实现如下:
public static void printBuddies(Pair<Employee> p){
Employee first=p.getFirst();
Employee second=p.getSecond();
System.out.println(first.getName()+second.getName());
}
前面讨论过,你不能传递Pair
public static void printBuddies(Pair<? extends Employee> p)
8.8.2通配符的超类型绑定
? super Manager
这个通配符被局限于任何Manager的超类。
通配符的超类绑定允许你对一个泛型对象写操作,通配符的子类绑定允许你对泛型对象读操作。