笔友城堡 - 可定义的个人主页

前言

面试中会问泛型相关内容,这里简单做一下记录,记录于此,方便自己查看和学习。

正文

Java泛型通过编译期类型检查提升安全性,采用类型擦除实现,配合 PECS 原则 正确使用通配符,是编写健壮、可维护代码的关键。

泛型

泛型(Generics)用于在编译期提供类型检查和类型安全。

主要目的:

  1. 类型安全:避免 ClassCastException
  2. 消除强制类型转换
  3. 提高代码复用性和可读性

Java泛型是伪泛型

  • Java泛型只在编译期生效
  • 编译后泛型信息会被擦除,替换为:
    • 无界泛型 → Object
    • 有界泛型 → 边界类型
List<String> list = new ArrayList<>();
// 编译后等价于
List list = new ArrayList();

为什么要用擦除?

为了 向后兼容

上界通配符 <? extends T>

上界通配符是用来“读”

List<? extends Number> list;

表示:list 中存放的是 Number 或其子类

特点:

  • 可以读取为 Number
  • 不能添加元素(除了 null

原因:

List<Integer> ints = new ArrayList<>();
List<? extends Number> nums = ints;
nums.add(1); // ❌ 编译错误

编译器不知道具体是 Integer / Double / Long

Producer(生产者)→ extends

下界通配符 <? super T>

下界通配符是用来“写”

List<? super Integer> list;

表示:list 中可以存放 Integer 及其父类

特点:

  • 可以添加 Integer
  • 读取只能是 Object

Consumer(消费者)→ super

PECS原则

Producer Extends, Consumer Super

生产者Extends,消费者Super

场景用法
只从中取数据<? extends T>
只往里写数据<? super T>
既要读又要写不用通配符

泛型方法 vs 泛型类

  1. 泛型类
    class Box<T> {
        private T value;
    }
  2. 泛型方法
    public <T> T getValue(T t) {
        return t;
    }

泛型方法不依赖类是否泛型

<T extends Comparable<T>>是什么?

public static <T extends Comparable<T>> T max(T a, T b)

含义:

  • T 必须是 Comparable 的实现类
  • 用于排序、比较

为什么不能 new T()

T t = new T(); // ❌

原因:

  • 泛型擦除后变成 Object
  • JVM 不知道具体类型

解决方案:

  • 传入 Class<T>
T t = clazz.newInstance();

为什么不能创建泛型数组?

List<String>[] lists = new List<String>[10]; // ❌

原因:

  • 数组是 协变的
  • 泛型是 不变的
  • 会导致运行时类型安全问题

正确方式:

List<?>[] lists = new List<?>[10];

泛型与反射的问题

  • 运行时泛型信息被擦除
  • 反射无法直接获取泛型类型
  • 可通过 Type/ ParameterizedType间接获取
ParameterizedType type =
    (ParameterizedType) getClass().getGenericSuperclass();

参考文章

AI

相关网址

笔友城堡 - 可定义的个人主页

暂无评论

评论审核已启用。您的评论可能需要一段时间后才能被显示。

none
暂无评论...