首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【关于Java的泛型(高级)】

【关于Java的泛型(高级)】

作者头像
艾伦耶格尔
发布2025-08-28 15:37:44
发布2025-08-28 15:37:44
1500
举报
文章被收录于专栏:Java基础Java基础

上一篇我们聊了泛型的基础——怎么用。 今天,我们来揭开泛型的底层原理。


一、泛型的“假象”——类型擦除(Type Erasure)

你有没有想过:为什么 Java 的泛型不能用于 new T() 或判断 if (obj instanceof T)

答案就藏在 Java 泛型的核心机制中:类型擦除(Type Erasure)

1. 什么是类型擦除?

简单说:泛型只存在于编译期,运行时会被“擦掉”

Java 的泛型是通过“类型擦除”实现的,也就是说:

  • ✅ 编译时:编译器用泛型做类型检查,确保类型安全。
  • ❌ 运行时:JVM 根本不知道泛型的存在,所有的泛型信息都被“擦除”了。
举个例子:
代码语言:javascript
复制
List<String> strList = new ArrayList<>();
List<Integer> intList = new ArrayList<>();

// 问:这两个 List 的运行时类型一样吗?
System.out.println(strList.getClass() == intList.getClass()); // 输出:true

你没看错!输出是 true

因为在运行时,List<String>List<Integer> 都变成了 List,泛型信息被擦除了。

2. 擦除后变成什么?
  • 如果没有限定类型(比如 <T>),擦除后变成 Object
  • 如果有限定类型(比如 <T extends Number>),擦除后变成上限类型(这里是 Number)。
代码语言:javascript
复制
public class Box<T extends Number> {
    private T value;
    public T getValue() { return value; }
}

编译后相当于:

代码语言:javascript
复制
public class Box {
    private Number value;  // T 被擦除为 Number
    public Number getValue() { return value; }
}
3. 为什么要类型擦除?

这是 Java 为了兼容老版本(Java 5 之前没有泛型)而做的设计。它让泛型代码可以和非泛型代码共存,但代价是:

  • 不能在运行时获取泛型类型
  • 不能 new T()
  • 不能 instanceof T

二、通配符的上下限:? extends T 和 ? super T

泛型中有一个非常重要的概念:通配符(Wildcard),尤其是它的上下限用法。

1. ? extends T —— 上限通配符(Upper Bounded Wildcard)

表示“某种类型,它是 T 或 T 的子类”。

代码语言:javascript
复制
List<? extends Number> list;

这个 list 可以是:

  • List<Number>
  • List<Integer>
  • List<Double>
  • ……

但你不能往里面添加元素(除了 null),因为编译器不知道具体是哪种子类型。

代码语言:javascript
复制
list.add(new Integer(1)); // ❌ 编译错误!
Number n = list.get(0);   // ✅ 可以读取,因为一定是 Number 或其子类

👉 适用场景:只读操作(Producer)

2. ? super T —— 下限通配符(Lower Bounded Wildcard)

表示“某种类型,它是 T 或 T 的父类”。

代码语言:javascript
复制
List<? super Integer> list;

这个 list 可以是:

  • List<Integer>
  • List<Number>
  • List<Object>

你可以往里面添加 Integer 或其子类:

代码语言:javascript
复制
list.add(new Integer(1)); // ✅ 可以添加
Object obj = list.get(0); // ❌ 只能拿到 Object,类型信息丢失

👉 适用场景:只写操作(Consumer)


三、PECS 原则:搞定上下限的“黄金口诀”

记不住什么时候用 extends,什么时候用 super?记住这个口诀:

PECS = Producer-Extends, Consumer-Super

  • 如果你从集合中读取数据(它是“生产者”),用 ? extends T
  • 如果你往集合中写入数据(它是“消费者”),用 ? super T
举个 JDK 中的经典例子:Collections.copy()
代码语言:javascript
复制
public static <T> void copy(List<? super T> dest, List<? extends T> src)
  • src 是“生产者” → 用 ? extends T(从里面读 T 类型的数据)
  • dest 是“消费者” → 用 ? super T(往里面写 T 类型的数据)

完美符合 PECS!


四、泛型的局限性(你知道吗?)

由于类型擦除,Java 泛型有一些“坑”:

限制

说明

❌ 不能创建泛型数组

new T[] 不合法,因为运行时不知道 T 是什么

❌ 不能用于基本类型

List<int> 不行,要用 List<Integer>

❌ 不能用于 instanceof

obj instanceof List<String> 不合法

❌ 静态变量不能使用泛型类型

private static T t; 不合法,因为静态变量属于类,而泛型是实例相关的


五、面试高频问题(附参考回答)

Q1:Java 泛型是怎么实现的?为什么叫“伪泛型”?

A:Java 泛型是通过“类型擦除”实现的,泛型信息只在编译期存在,运行时会被擦除。因此它被称为“伪泛型”,与 C# 的“真泛型”不同。

Q2:List<Object> 和 List<String> 有继承关系吗?

A:没有!List<String> 不是 List<Object> 的子类。这是泛型的“不可变性”。如果需要兼容,要用通配符,比如 List<? extends Object>

Q3:? extends T 和 ? super T 有什么区别?什么时候用?

A:? extends T 表示 T 及其子类,适合“读取”;? super T 表示 T 及其父类,适合“写入”。遵循 PECS 原则:生产者用 extends,消费者用 super


六、总结:泛型的本质

概念

关键点

类型擦除

泛型只在编译期存在,运行时被擦除为 Object 或上限类型

通配符

? 表示未知类型,extends 是上限,super 是下限

PECS 原则

生产者用 extends,消费者用 super

局限性

不能 new T、不能用基本类型、不能 instanceof 等


写在最后

Java 泛型看似简单,实则暗藏玄机。理解了类型擦除PECS 原则,你就掌握了泛型的“内功心法”。

下次面试官再问:“说说泛型的原理”,你就可以从容不迫地说:

“Java 泛型基于类型擦除实现,编译期检查类型安全,运行时擦除泛型信息。为了灵活处理类型兼容,我们使用 ? extends T? super T,并遵循 PECS 原则……”

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-08-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、泛型的“假象”——类型擦除(Type Erasure)
    • 1. 什么是类型擦除?
    • 举个例子:
    • 2. 擦除后变成什么?
    • 3. 为什么要类型擦除?
  • 二、通配符的上下限:? extends T 和 ? super T
    • 1. ? extends T —— 上限通配符(Upper Bounded Wildcard)
    • 2. ? super T —— 下限通配符(Lower Bounded Wildcard)
  • 三、PECS 原则:搞定上下限的“黄金口诀”
    • 举个 JDK 中的经典例子:Collections.copy()
  • 四、泛型的局限性(你知道吗?)
  • 五、面试高频问题(附参考回答)
    • Q1:Java 泛型是怎么实现的?为什么叫“伪泛型”?
    • Q2:List<Object> 和 List<String> 有继承关系吗?
    • Q3:? extends T 和 ? super T 有什么区别?什么时候用?
  • 六、总结:泛型的本质
  • 写在最后
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档