无界通配符 List 和原始类型 List 在字节码层面完全一致:二者均被擦除为原始类型 List,编译后签名均为 Ljava/util/List;,JVM 无法区分,运行时 getClass()、instanceof 等操作结果相同。

无界通配符 List> 和原始类型 List 在 JVM 字节码层面确实是完全一致的——它们编译后生成的字节码类签名、字段类型、方法参数与返回值类型全部相同,JVM 无法区分二者。
字节码表现完全相同
Java 编译器对两者都执行类型擦除,且擦除目标均为原始类型 List:
-
List>→ 擦除为List -
List(原始类型)→ 本身就是List
反编译后的字节码中,二者在 ConstantPool、Signature 属性(若存在)及所有指令操作数中均表现为 Ljava/util/List;。JVM 只认这个符号引用,不感知泛型信息。
运行时无任何区别
JVM 加载类时只校验原始类型是否匹配。例如:
立即学习“Java免费学习笔记(深入)”;
-
list instanceof List对两者都返回true -
list.getClass() == ArrayList.class对两者结果一致 - 反射获取的
Field.getGenericType()可能不同(源码保留),但Field.getType()均返回Class<list></list>
关键验证方式
可通过以下任一手段实证一致性:
- 用
javap -c -s查看编译后字节码:两个声明生成的descriptor字段完全相同(如Ljava/util/List;) - 使用 ASM 或 Byte Buddy 动态读取类文件结构,比对常量池和方法签名项
- 在运行时通过
Unsafe或 JVMTI 获取实际加载的类元数据,确认无额外泛型标记
为什么不能用 instanceof 区分它们
因为 instanceof 操作仅作用于运行时对象的实际类(即 ArrayList 等实现类),而泛型信息早已被擦除。无论变量声明是 List> 还是 List,其底层对象都是同一份字节码实例,JVM 视为同质。


















