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

Java 泛型核心机制与实战指南

Java 泛型通过类型参数在编译阶段提供类型安全,避免强制转换错误。核心涉及泛型类定义、类型边界约束及类型擦除机制。通配符 ? extends 和 ? super 分别用于读取和写入场景。需注意泛型不支持基本类型、无法创建泛型数组等限制。掌握这些特性有助于编写更健壮、可复用的 Java 代码。

念念不忘发布于 2026/3/22更新于 2026/7/631 浏览
Java 泛型核心机制与实战指南

Java 泛型核心机制与实战指南

泛型是 Java 语言中实现类型安全的重要特性。它允许我们在编译阶段就检查类型,避免运行时的强制转换错误,同时提升代码的可复用性。

泛型类

基本语法

定义泛型类时,需要在类名后使用尖括号声明类型参数:

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

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

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

实际应用

实例化泛型类时,必须指定具体的类型实参。这能让编译器知道容器里装的是什么。

class MyArray<T> {
    public 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> {
    public 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 class Test {
    public static void main(String[] args) {
        // MyArray<String> myArray1 = new MyArray<>(); // 编译错误,String 不是 Number 的子类型
        MyArray<Integer> myArray = new MyArray<>(); // 正常,Integer 是 Number 的子类型
    }
}

一个典型的例子是寻找数组中的最大值,这需要元素具备比较能力:

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 在运行时并不保留泛型信息。这意味着 List<String> 和 List<Integer> 在运行时都被视为原始类型 List。

编译器在类型擦除阶段主要做了以下几件事:

  1. 移除类型参数:字节码中不再包含泛型参数信息。
  2. 替换为原始类型或上界:如果没有指定上界,泛型参数会被替换为 Object;如果指定了(如 T extends Comparable<T>),则替换为上界类型。
  3. 插入类型转换:为了保持类型安全,编译器会在读取元素的地方自动插入从 Object 到具体类型的强制转换。
  4. 生成桥接方法:为了保证与旧版本非泛型代码的兼容性,编译器可能会生成桥接方法。

这种机制确保了泛型代码能与非泛型代码无缝对接,但也带来了一些限制,比如无法在运行时直接获取泛型的具体类型。

通配符

当不确定具体类型,或者需要更灵活的接口设计时,可以使用通配符 ?。

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

public class Test {
    // 可以传入任意类型的 Message
    public static void fun(Message<?> temp) {
        System.out.println(temp.getMessage());
    }
    
    public static void main(String[] args) {
        Message<String> message = new Message<>();
        message.setMessage("你好!");
        fun(message);
        
        Message<Integer> message2 = new Message<>();
        message2.setMessage(199);
        fun(message2);
    }
}

通配符上界 (? extends T)

主要用于读取数据。表示泛型参数必须是 T 或其子类。

  • 特点:不能添加任何元素(除了 null),因为编译器无法确定具体是哪一个子类,写入可能导致类型不安全。
  • 读取:返回类型为 T 或其父类(通常是 Object)。
class Food { }
class Fruit extends Food { }
class Apple extends Fruit { }
class Banana extends Fruit { }

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

public class Test1 {
    public static void funExtends(Message<? extends Fruit> temp) {
        System.out.println(temp.getMessage());
        // temp.setMessage(new Banana()); // 编译错误,无法确定具体类型
        Fruit fruit = temp.getMessage(); // 安全读取
    }
}

通配符下界 (? super T)

主要用于写入数据。表示泛型参数必须是 T 或其父类。

  • 特点:可以添加 T 或其子类的元素,因为这些类型都兼容下界。
  • 读取:只能确保是 Object 类型,因为可能是父类的任意一种。
class Plate<T> {
    private T plate;
    public T getPlate() { return plate; }
    public void setPlate(T plate) { this.plate = plate; }
}

public class Test1 {
    public static void funSuper(Plate<? super Fruit> temp) {
        // 此时可以修改,添加的是 Fruit 或者 Fruit 的子类
        temp.setPlate(new Apple());
        temp.setPlate(new Banana());
        
        System.out.println(temp.getPlate()); // 只能输出,无法强转为 Fruit
    }
}

泛型方法

泛型方法可以在调用时独立于类定义泛型参数。通常用于工具类方法。

class Alg2 {
    // 泛型方法,<T> 放在返回值类型之前
    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;
    }
}

public class Test2 {
    public static void main(String[] args) {
        Integer[] array = {1, 13, 51, 71, 19};
        Integer ret = Alg2.<Integer>findMax(array);
        System.out.println(ret);
    }
}

泛型的限制

虽然泛型很强大,但在使用时仍需注意以下限制:

  1. 不支持基本数据类型:泛型只能使用引用类型。需要使用 int 时请用 Integer。
  2. 不能创建泛型数组:由于类型擦除,new List<String>[10] 是不允许的。建议使用 ArrayList<List<String>> 替代。
  3. 不能实例化泛型对象:new List<String>() 是错误的,应使用具体实现类如 new ArrayList<>()。
  4. 运行时类型查询受限:由于擦除,instanceof 和 getClass() 无法检测泛型参数的具体类型。
  5. 泛型类型参数无继承关系:即使 A 是 B 的子类,List<A> 也不是 List<B> 的子类。
  6. 反射限制:反射无法直接获取泛型类型参数的具体信息。

掌握这些规则,能帮助你在编写 Java 代码时更好地利用泛型,既保证类型安全,又避免常见的坑。

目录

  1. Java 泛型核心机制与实战指南
  2. 泛型类
  3. 基本语法
  4. 实际应用
  5. 泛型上界
  6. 定义与使用
  7. 类型擦除
  8. 通配符
  9. 通配符上界 (? extends T)
  10. 通配符下界 (? super T)
  11. 泛型方法
  12. 泛型的限制
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Java 核心面试知识点整理:基础、并发与容器实战
  • 使用 LLaMA-Factory 训练 Qwen2.5-VL 进行目标检测
  • 计算机技能如何助力职业拓展与转型
  • 单链表数据结构详解与 C 语言实现
  • 文心一言 4.5 开源评测与本地部署实践
  • VS Code Java 开发环境配置指南:JDK 至 Spring Boot 插件
  • VSCode Copilot 接入智谱 GLM-5.1 实战指南
  • 网络安全常见十大漏洞总结:原理、危害与防御策略
  • 网络安全工程师零基础入门学习指南
  • 2026 年 3 月行业动态与开源生态全景报告
  • 双指针算法实战:移动零与复写零详解
  • Java OCR 实战:RapidOCR 快速集成与优化指南
  • Docker 多容器编排:Compose 实战教程
  • 前端网页开发基础:HTML、CSS 与 JavaScript 入门指南
  • iceoryx 附录:C++ 内存模型与原子操作详解
  • OpenClaw AI Agent 部署指南:基于腾讯云轻量应用服务器搭建
  • Web 安全实战:Robots.txt 协议原理、利用与防御
  • AI 重复率检测方法:4 步掌握 AIGC 内容识别与优化
  • Yolo11 基于 DroneVehicle 数据集的无人机视角下车辆目标检测
  • 自然语言处理在金融领域的应用与实战

相关免费在线工具

  • 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

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online