java泛型
从jdk1.5开始,java语言加入了泛型支持,泛型是一种编译时的约束,可以在编译阶段确定数据的类型。泛型是在 Java 平台上作为编译时转换实现的。编译器实际上生成与使用非泛型源代码时相同的字节指令,插入运行时类型转换以在每次访问时将值转换为正确的类型。尽管是相同的字节码,但是类型参数信息用 一个新的签名(signature) 属性记录在类模式中。JVM 在装载类时记录这个签名信息,并在运行时通过反射使它可用。
字节码分析
非泛型类
public class Box {
private Object object;
public void add(Object object) {
this.object = object;
}
public Object get() {
return object;
}
}
class 字节码信息
this class :Box
super class: Object
Fileds:
<Ljava/lang/Object;>
Methods:
add : <Ljava/lang/Object;()V>
get : <()Ljava/lang/Object;>
泛型类
public class Box<T> {
private T t; // T stands for "Type"
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
}
class 字节码信息
this class :Box
[0] Signature <T:<Ljava/lang/Object;><Ljava/lang/Object;>>
super class: Object
Fileds:
<Ljava/lang/Object;>
[0] Signature <TT;>
Methods:
add : <Ljava/lang/Object;()V>
[1] Signature <TT()V;>
get : <()Ljava/lang/Object;>
[1] Signature <()TT;>
通过查看字节码可以发现带泛型的类和不带泛型类只在Signature部分有区别。如上TT表明类使用泛型,泛型参数名称为T。
方法和构造函数范围泛型
泛型可以在方法或构造函数范围内声明,如下所示。它只在其声明的函数范围内有效。
public <U> void inspect(U u){
System.out.println("T: " + t.getClass().getName());
System.out.println("U: " + u.getClass().getName());
}
方法信息:
inspet : <Ljava/lang/Object;()V>
[1] Signature <<U:Ljava/lang/Object;>(TU)V;>
限定范围类型参数
public <U extends Number> void inspect(U u) {
System.out.println("T: " + t.getClass().getName());
System.out.println("U: " + u.getClass().getName());
}
方法信息:
inspet : <Ljava/lang/Number;()V>
[1] Signature <<U:Ljava/lang/Number;>(TU)V;>
还可以增加要实现的接口限制,如下:
public <U extends Number & Serializable> void inspect(U u) {
System.out.println("T: " + t.getClass().getName());
System.out.println("U: " + u.getClass().getName());
}
方法信息:
inspet : <Ljava/lang/Number;()V>
[1] Signature <<U:Ljava/lang/Number;Ljava/lang/Serializable;>(TU)V;>
泛型信息擦除
类型参数在编译的时候会被擦除,只保留不带类型参数的raw type,因此无法再运行上下文中使用泛型类型。如下面这段代码,编译时无法通过的。
public class MyClass<E> {
public static void myMethod(Object item) {
if (item instanceof E) { //Compiler error
...
}
E item2 = new E(); //Compiler error
E[] iArray = new E[10]; //Compiler error
E obj = (E)new Object(); //Unchecked cast warning
}
所以泛型参数只能出现在类,方法,属性的声明中。