跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava算法

Java 泛型核心机制、类型擦除与实战技巧

Java 泛型通过类型参数实现代码复用与类型安全。核心涉及泛型类定义、上界约束及通配符使用。运行时存在类型擦除机制,导致基本类型不可用、数组创建受限等。掌握 PECS 原则(Producer Extends, Consumer Super)能有效处理泛型边界问题。

人间失格发布于 2026/3/27更新于 2026/9/550 浏览
Java 泛型核心机制、类型擦除与实战技巧

Java 泛型核心机制、类型擦除与实战技巧

Java 泛型是语言层面的重要特性,它让我们在编译期就能获得类型安全,同时保持代码的复用性。不过,理解其背后的原理(尤其是类型擦除)对于编写健壮的泛型代码至关重要。下面我们从基础语法开始,逐步深入到边界约束和通配符的使用。

泛型类

语法规范

定义泛型类时,只需在类名后加上尖括号包裹的类型形参即可。

class ClassName<T1, T2, ..., Tn> {
    // 这里可以使用类型参数
}

如果需要继承,也可以指定父类的泛型参数:

class ClassName<T1, T2, ..., Tn> extends ParentClass<T1> {
    // 可以只使用部分类型参数
}

实际使用

实例化时,必须明确具体的类型实参。

MyArray<String> myArray = new MyArray<>();

下面是一个完整的示例,展示如何定义一个通用的数组容器:

class MyArray<T> {
    private Object[] array = new Object[10];

    public void set(int pos, T val) {
        array[pos] = val;
    }

    public T get(int pos) {
        return (T) array[pos];
    }

    public Object[] getArray() {
        return array;
    }
}

public class Test {
    public static void main(String[] args) {
        MyArray<String> myArray = new MyArray<>();
    }
}

泛型上界

有时候我们需要对传入的类型变量做约束,比如要求它必须是某个类的子类。这时可以用 extends 关键字来定义上界。

定义与使用

class MyArray<T extends Number> {
    // ...
}

如果尝试传入非 Number 的子类(如 String),编译器会直接报错。这保证了我们在方法内部调用 Number 特有方法时的安全性。

再看一个更实用的例子,利用 Comparable 接口找出数组中的最大值:

class Alg<T extends Comparable<T>> {
    public T findMax(T[] array) {
        T max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i].compareTo(max) > 0) {
                max = array[i];
            }
        }
        return max;
    }
}

类型擦除

这是 Java 泛型最'坑'但也最关键的地方。JVM 在运行时并不保留泛型信息,所有的泛型类型都会被擦除为原始类型(Raw Type)。

这意味着 List<String> 和 List<Integer> 在运行时都是 List。为了弥补这一点,编译器会在编译阶段做几件事:

  1. 移除类型参数:字节码中不再包含泛型信息。
  2. 替换为上界:如果没有显式上界,默认替换为 Object;如果有,则替换为指定的上界。
  3. 插入类型转换:在读取元素时,编译器会自动插入强制类型转换代码。
  4. 生成桥接方法:为了保证与旧版本代码的兼容性,可能会生成额外的桥接方法。

这种机制虽然牺牲了运行时的多态性,但换来了向后兼容性和性能上的稳定。

通配符

当不确定具体类型,但又想操作泛型集合时,可以使用通配符 ?。

通配符上界 <? extends T>

主要用于读取数据(PECS 原则中的 Producer Extends)。

class Message<T> {
    private T message;
    public T getMessage() { return message; }
    public void setMessage(T message) { this.message = message; }
}

public static void funExtends(Message<? extends Fruit> temp) {
    System.out.println(temp.getMessage()); 
    // 注意:不能调用 setMessage,因为编译器不知道具体是 Apple 还是 Banana
}

通配符下界 <? super T>

主要用于写入数据(PECS 原则中的 Consumer Super)。

class Plate<T> {
    private T plate;
    public T getPlate() { return plate; }
    public void setPlate(T plate) { this.plate = plate; }
}

public static void funSuper(Plate<? super Fruit> temp) {
    // 可以添加 Fruit 或其子类
    temp.setPlate(new Apple()); 
    temp.setPlate(new Banana());
    
    // 读取时只能当作 Object 处理
    System.out.println(temp.getPlate());
}

泛型方法

泛型方法独立于类,可以在静态上下文中使用。

class Alg2 {
    public static <T extends Comparable<T>> T findMax(T[] array) {
        T max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i].compareTo(max) > 0) {
                max = array[i];
            }
        }
        return max;
    }
}

// 调用时显式指定类型
Integer ret = Alg2.<Integer>findMax(array);

泛型的限制

在使用泛型时,有几个常见的坑需要避开:

  1. 基本类型不可用:不能用 int、double 等作为类型参数,必须用包装类(如 Integer)。
  2. 泛型数组创建受限:由于类型擦除,new List<String>[10] 是不允许的。
  3. 无法实例化泛型对象:new List<String>() 错误,应使用 new ArrayList<>()。
  4. 运行时类型查询:instanceof 或 getClass() 无法获取泛型的具体类型参数。
  5. 无继承关系:List<A> 不是 List<B> 的子类,即使 A 是 B 的子类。
  6. 反射限制:反射无法直接获取泛型参数的具体信息。

掌握这些规则,配合类型擦除的理解,就能写出既安全又灵活的 Java 泛型代码了。

目录

  1. Java 泛型核心机制、类型擦除与实战技巧
  2. 泛型类
  3. 语法规范
  4. 实际使用
  5. 泛型上界
  6. 定义与使用
  7. 类型擦除
  8. 通配符
  9. 通配符上界 <? extends T>
  10. 通配符下界 <? super T>
  11. 泛型方法
  12. 泛型的限制

更多推荐文章

查看全部
  • VSCode Copilot 登录失败排查指南:常见问题与解决方案
  • Lostlife2.0 整合 LLaMA-Factory 引擎,增强 NPC 对话逻辑
  • Python 数据科学工具链入门:NumPy、Pandas、Matplotlib 实战
  • Windows 10 彻底关闭 Microsoft 365 Copilot 弹窗的 6 种方法
  • Stable Diffusion UnCLIP 2.1 技术解析与实操指南
  • Python 兼职平台推荐及接私活实战指南
  • 基于 Multi-Agent、Skills 与 Spring AI 构建自主决策智能体
  • Faster Whisper v1.7 本地部署教程:支持 AMD 显卡与日文转中文
  • ZeroClaw Gateway + LM Studio + Reflex 本地 AI 管理面板搭建
  • Seedance 2.0 实操教程:从入门到 AI 导演模式
  • C++ 网络编程实战:基于 TCP 协议的简易计算器
  • 人工智能(AI)核心面试题与实战解析
  • OpenClaw Web Search 工具配置与渠道详解
  • OSCP 实战:获取并破解 Net-NTLMv2 哈希(下)
  • Linux 内核 list_for_each_entry 链表遍历详解
  • 人工智能(AI)常见面试题及答案汇总
  • Linux 服务器部署 OpenClaw 教程
  • Java 串口通信库 jSerialComm 跨平台开发指南
  • Flutter 三方库 algolia_client_recommend 鸿蒙适配指南
  • 四款主流 AI 编程 IDE 横向评测:从辅助到代理的演进路径

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online