温馨提示×

温馨提示×

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

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

怎么理解java泛型擦除

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

理解 Java 泛型擦除(Type Erasure),可以从「是什么、为什么、怎么表现、有什么影响」四个层面来看。


一、什么是泛型擦除?

泛型擦除是指:

Java 在编译期会进行泛型类型检查,但在编译完成后(字节码中),泛型类型信息会被“擦掉”,统一替换为它们的上界或 Object。

简单说:

List<String> list = new ArrayList<>();

在 运行时,JVM 并不知道这是 List<String>,只知道是 List。


二、为什么要有泛型擦除?

这是 历史兼容性 决定的。

  • Java 5 才引入泛型
  • 之前已存在大量 List、Map 代码
  • 如果运行时保留泛型 → 旧代码无法兼容

所以 Java 采用 编译期泛型 + 运行时擦除 的方案,实现:

  • 编译期类型安全
  • 兼容旧版本 JVM 和字节码

✅ 这是一种“妥协式设计”


三、擦除后到底变成什么?

1️⃣ 无界泛型 → Object

class Box<T> {
    T value;
}

擦除后:

class Box {
    Object value;
}

2️⃣ 有界泛型 → 上界

class Box<T extends Number> {
    T value;
}

擦除后:

class Box {
    Number value;
}

3️⃣ 方法签名中的泛型也会被擦除

void print(List<String> list)

编译后等价于:

void print(List list)

四、泛型擦除带来的“奇怪现象”

❌ 1. 不能 new T()

T obj = new T(); // 编译错误

原因:运行时不知道 T 是什么


❌ 2. 不能创建泛型数组

T[] arr = new T[10]; // 错误

但允许:

List<String>[] arr = new List[10]; // 警告,但不安全

❌ 3. 泛型不能用于 instanceof

if (obj instanceof List<String>) // 错误

只能:

if (obj instanceof List)

❌ 4. 方法重载“看起来不同,其实一样”

void test(List<String> list) {}
void test(List<Integer> list) {}

❌ 编译错误(签名擦除后相同)


五、那泛型信息完全没了吗?

不是 完全没。

在以下地方仍保留泛型信息(通过 反射 + 元数据):

  • 类字段声明
  • 方法参数
  • 方法返回值
  • 父类泛型

例如:

class MyList extends ArrayList<String> {}

可以通过:

MyList.class.getGenericSuperclass()

拿到 ArrayList<String>

⚠️ 但 对象实例本身不保存泛型


六、一句话总结

Java 泛型是“编译期的语法糖”,运行时不存在泛型。

✅ 编译期:帮你检查类型
❌ 运行期:擦成 Object / 上界

如果你愿意,我也可以:

  • 用 字节码 给你看擦除结果
  • 讲 桥接方法(bridge method)
  • 对比 Kotlin / C# 的泛型实现

你是更偏「面试理解」还是「源码级理解」?

向AI问一下细节

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

AI
助
手