泛型是JDK 5引入的参数化类型机制,核心是在编译期锁定数据类型以保障类型安全;它仅在编译期有效,运行时被擦除为Object,故无法通过T.class获取实际类型。

泛型 是 Java 在 JDK 5 引入的参数化类型机制,它的核心作用就一条:让类型也能当参数传进去,从而在编译期锁定操作的数据类型。
不是运行时靠猜,也不是靠 (Dog) obj 强转硬扛——它把类型安全这件事,提前到写完代码、还没点运行按钮的时候就给你拦住。
为什么 ArrayList<String> 比 ArrayList 好用?
因为前者在编译期就能拒绝 list.add(123) 这种错,后者要等到运行时 ClassCastException 才暴雷。
- 没泛型:往
ArrayList里塞Integer、Dog、Runnable全都合法,取出来全得手动强转,错一个就崩 - 有泛型:
ArrayList<String>编译直接报错add(int)不匹配,连.get(0)返回值也不用 cast,自动就是String - 注意:泛型只在编译期起作用,字节码里已经擦除成
Object—— 所以不能用if (T.class == String.class)这类运行时判断
泛型方法怎么写?什么时候必须加 <T>?
静态方法没法蹭类上定义的 T,所以只要它要用泛型,就得自己声明 <T>。
立即学习“Java免费学习笔记(深入)”;
- 错误写法:
public static void wrong(T t) { ... }→ 编译不过,T未定义 - 正确写法:
public static <T> void right(T t) { ... }→<T>必须紧挨static,位置不能错 - 返回值是泛型时也一样:
public static <T> T getValue() { return null; } - 非静态方法在泛型类里可以省略
<T>:class Box<T> { public T getContent() { ... } }
泛型通配符 ?、? extends T、? super T 怎么选?
它们不是语法糖,是解决「父子类集合不能赋值」这个硬伤的补丁。
-
List<Object>≠List<String>,哪怕String是Object子类 —— 泛型不协变 - 读多写少?用
? extends T:void print(List<? extends Number> list)可传ArrayList<Integer>,但不能add(...)(编译器不知道具体子类型) - 写多读少?用
? super T:void addNum(List<? super Integer> list)可传ArrayList<Number>或ArrayList<Object>,但get(0)只能当Object用 - 完全不确定?
?最保守,只能调用size()、clear()这类与类型无关的方法
泛型擦除是绕不开的底层事实:你写的 <String>、<List<User>> 到运行时全变成 Object,所有类型检查和隐式转换都是编译器悄悄帮你补的。这意味着反射拿不到泛型实际类型,new T[] 会报错,类型判断只能靠 instanceof 实例而非 T.class。










