Java 泛型中的 T、E、K、V、?到底啥意思?
——2025 年了,还在懵?看完这张表直接秒懂,再也不被面试官吊打
| 符号 | 官方/社区约定含义 | 最常见出现场景 | 真实项目里谁在用(2025 年真实案例) | 能不能随便换? |
|---|---|---|---|---|
| T | Type(任意类型) | 类泛型定义最通用写法 | class Cache<T>public <T> T get(String key) | 99% 的自定义泛型类/方法 |
| E | Element(集合元素) 集合框架专用 | List<E>、Set<E>、Map.Entry<K,V> | JDK 源码、所有集合类 | 只能用于集合相关,换了会被打 |
| K | Key(键) Map 的 key | Map<K,V>、Cache<K,V> | 所有 Map、缓存、配置中心 | 只能表示 key,换了就乱套 |
| V | Value(值) Map 的 value | Map<K,V>、Result<V> | 所有返回值、缓存 value | 同上 |
| ? | Unknown(未知类型) 通配符,表示“任意类型” | List<?>、Comparator<? super T> | 工具类、兼容老代码、泛型擦除场景 | 不能在定义泛型时用,只能用在“使用”时 |
| N | Number(数字) 数字相关 | List<N extends Number> | 数字工具类 | 很少用 |
| R | Return Type(返回值类型) 函数式编程常用 | <R> R map(Function<T,R> mapper) | Stream、Optional、CompletableFuture | 越来越流行 |
| S、U | 第二、第三个类型参数 多泛型参数时用 | <S,U> BiFunction<T,S,U> | 函数式接口、复杂工具类 | 很少见 |
2025 年真实项目写法排行(大厂规范)
| 排名 | 写法示例 | 谁在用? | 为什么这么写? |
|---|---|---|---|
| 1 | public class Result<T> | 所有中大型项目返回包装类 | T 代表任意业务数据 |
| 2 | public interface Repository<T, ID> | Spring Data JPA 规范 | T=实体,ID=主键类型 |
| 3 | Map<String, Object> | 99% 的项目(虽然不规范) | 懒得定义 VO |
| 4 | PageResult<List<T>> | 所有分页接口 | 外层是包装,内层是具体类型 |
| 5 | <T> T getBean(Class<T> clazz) | Spring 工具类 | 返回值类型由调用方决定 |
| 6 | List<? extends User> | 协变:只能读,不能加 | PECS 原则 |
| 7 | List<? super Admin> | 逆变:只能写,不能读 | 生产者用 extends,消费者用 super |
面试官最爱问的 5 个灵魂问题 + 标准答案
| 问题 | 标准答案(背下来) |
|---|---|
| T 和 ? 的区别? | T 是类型占位符,必须在定义时声明;? 是通配符,使用时才出现,表示未知类型,不能加元素(只能 get) |
| 为什么 Map 用 K,V 而不是 T? | 因为有明确语义:Key 和 Value,阅读性强,IDE 提示更友好 |
List<? extends Animal> 能 add(null) 吗? | 能 add(null),但不能 add 任何 Animal 子类,因为编译器不知道具体类型 |
Comparator<? super T> 是什么意思? | 比较器可以接受 T 或 T 的父类,用于逆变,经典例子:Collections.sort() |
| 为什么 Spring 用 里不写类型? | 泛型推导(Diamond Operator),JDK7+ 特性,编译器自动推断 |
2025 年最正确的写法(直接抄作业)
// 推荐:语义清晰
public class Cache<K, V> { ... }
public class Result<T> process(T input) { ... }
public <R> PageResult<R> query(PageQuery query, Class<R> clazz) { ... }
// 不推荐:虽然能跑,但会被架构师打
public class Cache<T, V> { ... } // K 改成 T?别闹
public <T> T doSomething() { ... } // 随便用 T,阅读者一脸懵
List<?> list = new ArrayList<>(); // 完全不知道里面是什么
终极结论(2025 年面试/写代码必背)
“T = Type(万能)
E = Element(集合专属)
K V = Key Value(Map 专属)
? = 不知道,但肯定是某种类型(通配符)
记住这句口诀:
“定义用 T,集合 E,Map 永远 K 和 V,读多写少 extends,写多读少 super,啥也不知道问号 ?”
你现在项目里,有没有把 Map 写成 Map 的?
敢不敢贴出来让我帮你改成 K,V,顺便升个级?来!