泛型是编译期类型检查机制,非语法糖;其核心价值在于javac阶段拦截不安全操作,如ArrayList add(123)编译报错,而非运行时ClassCastException。

泛型不是语法糖,是编译期类型检查机制
Java泛型在字节码层面被擦除(type erasure),但它的核心价值不在运行时,而在编译期拦截不安全的类型操作。比如 ArrayList 不能 add(123),这个错误在 javac 阶段就报错,而不是等到运行时抛 ClassCastException。
常见误解是“泛型只是为了写起来方便”,其实它直接改变了 API 的契约表达能力——方法签名里出现 ,就是在声明:调用者必须提供一个具体类型,且该类型会贯穿整个方法逻辑链。
- 泛型类、泛型方法、通配符(
? extends T/? super T)各自解决不同场景:前者约束实例,后者约束参数传递边界 - 原始类型(raw type)如
ArrayList会绕过所有泛型检查,编译器只发警告(unchecked),但这是危险的退化行为 - 不能用基本类型实例化泛型,
List是非法的,必须写List;自动装箱不解决泛型擦除问题
为什么 ArrayList.get() 返回 Object,却能赋值给 String?
因为编译器在调用点插入了隐式强制转换。看这段代码:
ArrayListlist = new ArrayList<>(); list.add("hello"); String s = list.get(0); // 编译后实际是:String s = (String) list.get(0);
这个转型由编译器自动补全,并受泛型声明保护——如果 list 是 ArrayList,这行就会编译失败。所以不是 JVM 支持泛型,而是 javac 在擦除前做了类型推导和插入检查。
立即学习“Java免费学习笔记(深入)”;
- 擦除后
ArrayList和ArrayList都变成ArrayList,所以无法通过反射获取泛型实际类型(list.getClass().getTypeParameters()拿不到String) - 数组和泛型不兼容:
new ArrayList编译失败,因为泛型类型不可具体化(not reifiable)[10] - 静态方法/字段不能引用所在类的类型参数,
static T value是非法的
PECS 原则:什么时候用 extends,什么时候用 super?
这是泛型通配符最易混淆的点。记住一句话:Producer Extends, Consumer Super。即,如果你要从集合中「取」数据(producer),用 ? extends T;如果你要往集合中「放」数据(consumer),用 ? super T。
例如:
List extends Number> nums = new ArrayList(); // ✅ 可以 get() → 得到 Number 或子类 nums.add(3.14); // ❌ 编译错误:不知道具体是 Integer 还是 Double,不敢让写
List super Integer> ints = new ArrayList(); // ✅ 可以 add(Integer) ints.get(0); // ❌ 返回 Object,只能当 Object 用
-
? extends T允许读取,但禁止写入(除了null) -
? super T允许写入T及其子类,但读取只能当Object - 无界通配符
?等价于? extends Object,适合只调用size()、isEmpty()这类不依赖元素类型的方法
泛型方法比类泛型更灵活,但容易误用类型参数名
泛型方法的类型参数作用域仅限于该方法,和类的类型参数无关。常见错误是把方法类型参数和类参数同名,导致遮蔽(shadowing):
class Box{ T pick(T a, T b) { return a; } // ❌ T 遮蔽了类的 T,两者完全无关 }
应改用不同名称,比如 ,或直接利用类参数:
class Box{ T pick(T a, T b) { return a; } // ✅ 复用类泛型,语义清晰 U convert(U u) { return u; } // ✅ 明确是新类型 }
- 泛型方法可推断类型:调用
Utils.可简写为max(list) Utils.max(list),前提是参数类型足够明确 - 泛型方法不能重载仅靠返回类型区分:
和T get() U get()是同一个签名,编译失败 - 若方法逻辑不依赖类型参数(比如只是包装一层
return (T) obj;),说明可能不需要泛型,或者应改用@SuppressWarnings("unchecked")并加注释说明风险
Class)的尝试,都得绕道 Class 对象显式传入。








