← [ BACK_TO_NOTES ]

Java 泛型基础

泛型如何在编译期约束集合与 API:类型参数、边界、菱形推断,以及擦除带来的限制入口。

#concept #growing #dev #java

[!info] related notes

Java 泛型基础

这个概念为什么出现

旧版通用集合 API 以 Object 接收和返回元素,取出时常需强转,类型错误可能拖到运行时。泛型把“这是订单列表还是用户列表”变成编译期检查,同时通过类型擦除保持与旧 JVM 的兼容。

[!abstract] 一句话理解 泛型用类型参数在编译期约束 API 与集合元素类型;运行时大部分类型参数被擦除,因此不能 new T()/new T[] 等可具体化操作。

最小可运行示例

场景:仓库服务的通用“货架盒”只允许同类型货物

import java.util.ArrayList;
import java.util.List;

final class Box<T> {
    private final List<T> items = new ArrayList<>();
    void put(T item) {
        if (item == null) throw new IllegalArgumentException("item");
        items.add(item);
    }
    T get(int index) { return items.get(index); }
    int size() { return items.size(); }
}

public class BoxDemo {
    // 泛型方法:取首个非空;两者均为 null 时仍返回 null
    static <T> T firstNonNull(T a, T b) {
        return a != null ? a : b;
    }
    public static void main(String[] args) {
        Box<String> skuBox = new Box<>();
        skuBox.put("SKU-1");
        // skuBox.put(1); // 编译错误
        System.out.println(skuBox.get(0));
        System.out.println(firstNonNull(null, "X"));
    }
}

建议运行:

javac BoxDemo.java && java BoxDemo

期望输出:

SKU-1
X

结合场景再看三个关注点

  1. 错误在编译期暴露,不用等到生产 ClassCast。
  2. Box<String> 与 Box<Object> 不变(invariant)。
  3. 擦除限制在进阶篇展开,但现在起避免 raw type。

核心概念与准确模型

1. 类型参数

  • 类/接口:class Repo<T>
  • 方法:<T> T id(T x)
  • 多参数:Map<K,V>

2. 边界

class NumBox<T extends Number> { }

上界限制可用方法;通配符 ? extends/? super 服务 PECS(进阶常用)。

3. 菱形推断

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

4. 擦除直觉

  • List<String>.class 不合法;new ArrayList<String>().getClass() 与 new ArrayList<Integer>().getClass() 相同,因为它们使用同一个实现类。不同集合实现的运行时类仍可不同。
  • 不能依赖运行时 T 做 instanceof T

边界情况与反直觉行为

  1. 原始类型 List 绕过部分泛型约束,可能引入 unchecked 警告和运行时强转失败;并非关闭所有类型检查。
  2. 泛型数组创建受限。
  3. 桥接方法由编译器生成(反编译可见)。

常见误区

[!warning] 常见误区:到处 @SuppressWarnings(“unchecked”) 先修类型设计;压制警告只在边界层且有证明时。

工程实践

  1. 公共 API 全程泛型化,禁止 raw。
  2. PECS:从 List<? extends T> 读取为 T,不能插入任意 T;它并非不可修改,仍可能允许删除、清空或插入 null。List<? super T> 可接收 T,读取通常只能保证 Object;具体操作还受集合自身契约限制。
  3. Java 没有通用类型别名;复杂通配符可用泛型辅助方法或有领域含义的封装类简化。
  4. 与集合框架一起练:List/Map/Optional。

本节总结

  • 泛型=编译期安全 + 表达能力
  • 擦除=运行时限制来源
  • 不用 raw type

自测题

  1. 为什么不能写 new T()?
  2. List<String> 能否传给 List<Object> 参数?
参考答案
  1. T 不提供运行时构造目标,也不保证无参构造器;需要创建实例时可显式传入 Supplier<T>。
  2. 不能直接传(不变性);否则能放入 Integer 破坏类型安全。

延伸阅读与资料来源

资料类型支撑内容
Generics (Oracle Tutorial)教程泛型体系
JLS Types - Generics规范类型系统
创建于 2026/7/15 更新于 2026/10/6
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本