温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

java泛型编译后去哪了

发布时间:2026-10-21 10:57:49 来源:亿速云 阅读:98 作者:小樊 栏目:编程语言

在 Java 中,泛型在编译后会“被擦除”,这就是著名的 类型擦除(Type Erasure)。下面分层说明“泛型去哪了”。


1️⃣ 编译期:泛型存在

在 .java 源码阶段,泛型是真实存在的:

List<String> list = new ArrayList<>();
list.add("abc");
String s = list.get(0);

编译器会:

  • 检查泛型类型是否合法
  • 自动插入类型转换
  • 保证类型安全

✅ 编译期:泛型用于类型检查


2️⃣ 编译后(.class 文件):泛型被擦除

Java 编译器在生成 .class 文件时:

泛型信息被“擦除”

例如:

List<String>

编译后变成:

List

(在字节码中通常是 Ljava/util/List;)

擦除规则

泛型写法 编译后
T Object
T extends Number Number
List<String> List
Map<String, Integer> Map

✅ 运行期:没有泛型


3️⃣ 泛型“去哪了”?

✅ 一部分 → 编译时的类型检查

  • 非法泛型使用在编译期直接报错
  • 不需要运行期检查

✅ 一部分 → 自动插入的强制类型转换

源码:

String s = list.get(0);

编译后等价于:

String s = (String) list.get(0);

✅ 一部分 → 元数据(有限保留)

通过 反射 + 特殊结构 可以保留少量泛型信息:

  • 类定义上的泛型
  • 方法参数 / 返回值
  • 字段声明

例如:

class Box<T> {}

反射可获取:

Box.class.getTypeParameters();

但 new Box<String>() 中的 String 无法获取


4️⃣ 为什么 Java 要擦除泛型?

原因很现实:

  • ✅ 兼容旧版本 JVM(Java 5 之前)
  • ✅ 不需要修改字节码规范
  • ✅ 旧代码可以直接运行

代价:

  • 运行期无法真正区分 List<String> 和 List<Integer>
  • 不能用 instanceof List<String>
  • 不能 new T()

5️⃣ 哪些地方“看起来”还有泛型?

如下情况泛型信息会保留(在 Signature 属性 中):

class A<T> {}
void method(List<String> list) {}

反射可以读到,但:

  • 不是运行时类型
  • 只是“描述信息”

6️⃣ 一句话总结

Java 泛型只存在于编译期,编译后被擦除为 Object(或上限类型),并靠强制类型转换保证安全。

如果你愿意,我可以:

  • 用字节码(javap)给你看擦除结果
  • 讲 Bridge Method 为什么存在
  • 对比 Kotlin / C# 的泛型实现

你想看哪一个?

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI
助
手