Java泛型类型擦除编译结果与OCP教材不符问题咨询
问题解答
1. 教材描述没有错误,是对泛型擦除的生效范围理解有偏差
泛型擦除是运行时执行层面的规则,并不代表编译后的class文件会删除所有泛型相关信息:
- Java编译器默认会在class文件的
Signature属性中保留类、方法、字段的泛型定义元数据,这类数据仅用于反射解析、框架类型校验、反编译还原场景,完全不影响JVM实际执行代码的逻辑。 - JVM实际运行时执行的就是教材描述的擦除后逻辑:无上限的泛型参数会替换为
Object,调用端的类型强转由编译器自动插入,你反编译结果中唯一和原代码有差异的(String)强转行,就是擦除逻辑的直接体现。
2. 确实存在删除泛型元数据的编译选项
javac提供了-XDomitSignatureAttributes编译参数,开启该参数编译时会直接删除class文件中的Signature属性,此时再用FernFlower反编译,得到的就是和教材描述完全一致的、不带泛型标识的擦除后代码。默认编译不会开启该参数,因此常规编译出来的class文件都携带泛型元数据。
3. 查看实际执行逻辑的正确方式
不要依赖反编译工具还原的源码格式,直接使用JDK自带的字节码查看工具即可看到真实执行逻辑:
执行命令 javap -c -v Crate.class 可以得到如下核心信息:
contents字段的实际类型描述符为Ljava/lang/Object;,仅Signature属性标注了泛型标识TT;emptyCrate方法的实际返回值描述符为()Ljava/lang/Object;,仅Signature属性标注了泛型返回值()TT;- main方法调用
emptyCrate后,存在一行checkcast java/lang/String的字节码指令,就是编译器自动插入的强转逻辑,完全匹配教材的擦除后代码逻辑。
补充说明FernFlower的反编译逻辑
FernFlower反编译时会主动读取class文件中的Signature属性,将泛型定义还原为和源码一致的形式,属于反编译工具的便利性功能,不代表编译时没有做泛型擦除。
内容的提问来源于stack exchange,提问作者wgitscht
相关产品推荐
相关产品推荐

