Anthropic与SK海力士合作自研AI芯片:技术路线与产业影响分析
2026/7/29 9:01:19
Java 泛型详解(2025–2026 面试/实战最实用版)
泛型(Generics)是 Java 5 引入的最重要特性之一,到今天仍然是面试、代码审查、框架源码阅读中最常考察的点。
下面按从基础到高阶的顺序,把最容易混淆、最常踩坑、最有价值的内容全部梳理一遍。
Listlist=newArrayList();list.add("hello");list.add(123);// 编译通过Strings=(String)list.get(1);// 运行时 ClassCastException// 没有泛型Strings=(String)list.get(0);// 有泛型List<String>list=newArrayList<>();Strings=list.get(0);// 无需强转| 写法位置 | 语法示例 | 含义 | 出现频率 |
|---|---|---|---|
| 类/接口 | class Box<T> | 类型参数 T,定义在类/接口级别 | ★★★★★ |
| 方法 | <E> void print(E e) | 方法级类型参数(独立于类泛型) | ★★★★☆ |
| 变量/参数 | List<String> list | 使用时指定具体类型 | ★★★★★ |
核心结论:
Java 泛型是编译期语法糖,在编译后会被擦除(类型参数被替换为 Object 或上界类型)。
擦除前后对比(字节码层面)
// 源代码List<String>list=newArrayList<>();list.add("hello");// 编译后(大致)Listlist=newArrayList();list.add("hello");// add(Object)Strings=(String)list.get(0);擦除带来的重要影响(常考)
List<String>list=newArrayList<>();System.out.println(list.getClass()==ArrayList.class);// trueSystem.out.println(listinstanceofList<String>);// 编译错误!// 运行时只能判断原始类型System.out.println(listinstanceofList);// trueclassBox<T>{staticTvalue;// 编译错误!staticvoidset(Tt){}// 编译错误!}T[]arr=newT[10];// 编译错误| 通配符写法 | 含义 | 能读(get) | 能写(add) | 经典使用场景 |
|---|---|---|---|---|
List<?> | 任意类型 | 只能得到 Object | 几乎不能写(只能加 null) | 作为只读参数 |
List<? extends Number> | Number 或其子类 | 可以 get 为 Number | 不能写 | “生产者”(Producer Extends) |
List<? super Integer> | Integer 的父类(包括 Integer) | 只能得到 Object | 可以写 Integer 及其子类 | “消费者”(Consumer Super) |
经典面试题:PECS 原则
Producer Extends:如果你要从集合中读取数据,用? extends
Consumer Super:如果你要向集合中写入数据,用? super
记忆口诀:
“读取用 extends,写入用 super”
// 最常见的三种泛型方法写法// 1. 普通泛型方法(最常用)publicstatic<T>voidprint(Tt){System.out.println(t);}// 2. 带返回值的泛型方法publicstatic<T>TgetFirst(List<T>list){returnlist.isEmpty()?null:list.get(0);}// 3. 泛型方法 + 多个类型参数publicstatic<K,V>Map<K,V>newMap(){returnnewHashMap<>();}注意:泛型方法前的<T>是方法级别的类型参数,与类泛型无关。
// 生产者(只读)voidprintNumbers(List<?extendsNumber>list){for(Numbern:list){// 安全读取System.out.println(n);}// list.add(1); // 编译错误}// 消费者(只写)voidaddIntegers(List<?superInteger>list){list.add(1);// 安全写入list.add(100);// OK// Integer x = list.get(0); // 编译错误,只能得到 Object}List<String>不是List<Object>的子类型?(类型不变量)<?>、<? extends T>、<? super T>分别能干什么、不能干什么?new T[]?(可以用反射绕过,但不推荐)(T[]) new Object[size])一句话本质:
Java 泛型是编译期类型检查 + 语法糖,运行时全部擦除为原始类型(或上界类型),靠编译器帮我们做类型转换。
最实用口诀(背下来就过关):
<T>,用时指定类型<T>,独立于类泛型extends,写入用super如果你能手写下面三段代码,就基本掌握泛型 80%:
List<String>为什么不能赋值给List<Object>需要更深入哪一块?
比如:
随时告诉我,我继续给你展开~