Java泛型本质是参数化类型,即在定义类、接口或方法时不绑定具体类型,使用时再指定,通过编译期类型检查实现代码复用与类型安全。

Java 泛型(Generic)本质是“参数化类型”——把类型当作变量来用,让类、接口或方法在定义时不绑定具体数据类型,而是在使用时才确定。它不是语法糖,也不是运行时特性,而是在编译期生效的类型检查机制。核心价值就两点:让代码既能复用,又不牺牲类型安全。
泛型解决了什么实际问题?
没有泛型时,集合类(如 ArrayList)只能存 Object,导致两个典型问题:
- 存错类型不报错:比如往本该装字符串的列表里加了一个整数,编译通过,但取出来强转成 String 时直接抛 ClassCastException
- 每次取值都要手动转型:写 (String) list.get(0) 不仅啰嗦,还容易写错、漏判
泛型把这类错误拦截在编译阶段。例如 List
泛型怎么写?常见形式有哪些?
泛型主要出现在三类结构中,写法有固定模式:
立即学习“Java免费学习笔记(深入)”;
-
泛型类:在类名后加 <T>,T 是类型参数(常用 T/E/K/V)。例如:
public class Box<T> { private T value; public void set(T value) { this.value = value; } } - 泛型接口:类似泛型类,如 interface Repository<T, ID> { T findById(ID id); }
- 泛型方法:在返回类型前声明类型参数,如 <T> void printArray(T[] arr)。注意:不是所有用了 T 的方法都是泛型方法,必须带 <T> 前缀
类型安全是怎么保障的?关键限制要知道
泛型的安全性来自编译器的静态检查,但有几个硬性规则必须遵守:
- 类型参数只能是引用类型:不能写 ArrayList<int>,得用包装类 ArrayList<Integer>
- 泛型信息在运行时被擦除(Type Erasure):JVM 看不到 List<String> 和 List<Integer> 的区别,它们都变成原始类型 List。所以无法用 instanceof 判断泛型类型,也不能直接 new T()
- 通配符增强灵活性:? extends Number 表示“某个 Number 的子类”,适合读取;? super Integer 表示“Integer 或其父类”,适合写入
初学者最容易忽略的细节
刚上手泛型时,这几个点常被跳过,却直接影响代码健壮性:
- 创建泛型对象时,JDK 7+ 支持菱形语法 new ArrayList<>(),但左边声明仍需明确类型,否则退化为原始类型,失去类型检查
- 子类继承泛型父类时,如果子类不是泛型类,必须指定父类的具体类型,如 class StringBox extends Box<String>
- 泛型类的不同实例(如 Box<String> 和 Box<Integer>)在运行时是同一个 Class 对象,只是编译期多了类型约束


















