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
}
所以泛型参数只能出现在类,方法,属性的声明中。
分享到:
相关推荐
- 泛型擦除前的例子把这段Java代码编译成Class文件,然后再用字节码反编译后,將会发现泛型都不见了,又变回了Java泛型出现之前的写法,泛型类型都变回了原
本文介绍了Java 5中添加的...javac中不支持的-target jsr14选项可以为某些Java 5语言特性生成与JDK 1.4兼容的字节码,并且开源的Retroweaver和Retrotranslator项目能把多数Java 5字节码转换成与Java 1.4兼容的字节码。
泛型擦除不是泛型丢失了,而是在编译后的字节码文件中使用单独的标识来存储泛型了。 为什么会出现泛型擦除,主要是为了编译器的兼容性。 因为在jdk5之前是没有泛型的,jdk5之后出现了泛型。 为了编译器的兼容性...
JVM 是可运行 Java 代码的假想计算机 ,包括一套字节码指令集、一组寄存器、一个栈、 一个垃圾回收,堆 和 一个存储方法域。JVM 是运行在操作系统之上的,它与硬件没有直接 的交互。 3. JAVA 集合 集合类存放于 ...
java字节码 java类加载 java线程 java垃圾回收 java泛型 java注解 java反射与动态代理 javaI/O java安全 java对象序列化
它首先将源代码编译成字节码,再依赖各种不同平台上的虚拟机来解释执行字节码,从而具有“一次编写,到处运行”的跨平台特性。在早期JVM中,这在一定程度上降低了Java程序的运行效率。但在J2SE1.4.2发布后,Java的...
java深度历险 InfoQ中文站 1、java字节码操作 2、java类的加载、链接和初始化 3、java线程 4、java垃圾回收机制与引用类型 5、java泛型 6、java注解 7、java反射与动态代理 8、javaI/O 9、java安全 10、java对象序列...
JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...
Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...
Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...
这些源代码可以被Java编译器编译成字节码,然后在Java虚拟机(JVM)上运行。Java是一种面向对象的编程语言,广泛应用于各种应用场景,从桌面应用到大型企业级应用,从移动应用到嵌入式系统。 适合人群:大学生、...
这些源代码可以被Java编译器编译成字节码,然后在Java虚拟机(JVM)上运行。Java是一种面向对象的编程语言,广泛应用于各种应用场景,从桌面应用到大型企业级应用,从移动应用到嵌入式系统。 适合人群:大学生、...
这些源代码可以被Java编译器编译成字节码,然后在Java虚拟机(JVM)上运行。Java是一种面向对象的编程语言,广泛应用于各种应用场景,从桌面应用到大型企业级应用,从移动应用到嵌入式系统。 适合人群:大学生、...
这些源代码可以被Java编译器编译成字节码,然后在Java虚拟机(JVM)上运行。Java是一种面向对象的编程语言,广泛应用于各种应用场景,从桌面应用到大型企业级应用,从移动应用到嵌入式系统。 适合人群:大学生、...
这些源代码可以被Java编译器编译成字节码,然后在Java虚拟机(JVM)上运行。Java是一种面向对象的编程语言,广泛应用于各种应用场景,从桌面应用到大型企业级应用,从移动应用到嵌入式系统。 适合人群:大学生、...
这些源代码可以被Java编译器编译成字节码,然后在Java虚拟机(JVM)上运行。Java是一种面向对象的编程语言,广泛应用于各种应用场景,从桌面应用到大型企业级应用,从移动应用到嵌入式系统。 适合人群:大学生、...