Java--泛型的约束和局限性

2018-02-27 11:50:39来源:oschina作者:Superheros人点击

分享

要讨论泛型的约束和局限性,必须先了解Java的类型擦除。


类型擦除:

Java虚拟机内没有泛型类型对象----所有对象都属于普通类。因此无论何时定义一个泛型类型,都自动提供一个相应的原始类型。原始类型的名字就是删去类型参数后的泛型类型名。擦除类型变量,并替换为限定类型(无限定的变量用Object)。例如:


public class Interval implements Serializable{
private T lower;
public Interval(T first, T second){...}
}
//原始类型如下:
public class Interval implements Serializable{
private Comparable lower;
public Interval(Comparable first, Comparable second){...}
}

泛型方法也存在类型擦除,其工作原理和泛型类的擦除一致。


总之,Java的类型擦除需要记住4点:

虚拟机中没有泛型,只有普通的类的方法。
所有的类型参数都用它们的限定类型替换。
桥方法被合成用来保持多态。
为了保持类型的安全性,必要时插入强制类型转换。 约束和局限性:

1、不能用基本数据类型替代类型参数。


没有Piar,只有Piar。其原因是类型擦除,擦除之后Piar类只有Object类型域,而Object不能存储double。


2、运行时类型查询只适用于原始类型。


试图查询一个对象是否属于某个泛型时,倘若使用instanceof会得到一个编译错误,如果使用强制类型转换会得到一个warning。例如:


if(a instanceof Pair) //Error
if(a instanceof Pair) //Error
Pair p = (Pair) a; //warning. 只能测试出a是一个Pair

同样的道理,getClass方法总是返回原始类型。


Pair s = new Pair(...);
Pair e = new Pair(...);
if(s.getClass == e.getClass)//true,它们是相等的,因为都返回的是Pair.class

3、不能创建参数化类型的数组。


不能实例化参数化类型的数组,如:


Pair[] table = new Pair[10];//error

因为类型擦除后,table[]的类型变成了Object[], 数组的类型是不能改变的,所以我们试图向table[]中存入其他类型的数据就会出错。


需要说明的是,只是不能用new Pair[10]这类语句创建数组,但是可以声明它的句柄,如Pair[] table;是完全合法的。


4、不能实例化类型变量。


不能使用像new T(...)、new T[...]或T.class这样的表达式中的类型变量,例如:


public Pair(){ first = new T(); }//Error

5、不能构造泛型数组。


就像上一条不能实例化类型变量一样,也不能实例化数组。


public static T[] minmax(T[] a){ T[] mm = new T[2];}//error

类型擦除会让这个方法永远无法构造Comparable[2]数组。


6、泛型类的静态上下文中类型变量无效。


不能在静态域或方法中引用类型变量,如:


public class Sing{
private static T sing; //Error
public static T getSing(){} //Error
}

7、不能抛出或捕获泛型类的实例。


既不能抛出也不能捕获泛型类的对象。实际上,甚至泛型类拓展Throwable都是不合法的。


public class Problem extends Exception{/*...*/} //Error

catch子句不能使用类型变量,但在异常规范中允许使用。


public static void work throws T{ //OK
try{
//...
}catch(T e){//Error
}
}

8、可以消除对受查异常的检查。


9、注意擦除后的冲突。

最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台