java泛型核心是解决运行时classcastexception风险,通过类型擦除将类型检查提前至编译期;泛型参数在运行时被擦除为object或上界类型,故无法反射获取实际类型;通配符遵循pecs原则:生产用extends、消费用super。

Java泛型常见面试真题,核心不是背答案,而是理解“为什么这么设计”和“不这么写会出什么问题”。下面从几个高频真题切入,讲清楚关键逻辑和实用判断。
泛型到底解决了什么问题?
不加泛型的集合(比如 List list = new ArrayList();)内部用 Object[] 存数据,取出来全是 Object,用前必须强转:
String s = (String) list.get(0); // 编译通过,但运行时可能 ClassCastException
泛型把类型检查提前到编译期。List<string></string> 在编译时就禁止往里加 Integer,也自动推导 get() 返回 String,不用强转——错误在写代码时就被拦住,而不是等运行崩了才暴露。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
为什么运行时拿不到泛型的实际类型?
因为 Java 用的是类型擦除(Type Erasure):
- 编译后,
ArrayList<string></string>和ArrayList<integer></integer>都变成原始类型ArrayList; - 泛型参数
<string></string>被擦成Object(无边界时)或上界类型(如<t extends number></t>擦成Number); - 所以
list.getClass().getTypeParameters()拿不到String,instanceof List<string></string>语法也不合法。
这设计是为了兼容 JDK 5 之前的字节码,但代价是运行时类型信息丢失。
通配符 ? extends T 和 ? super T 怎么选?
记住一句话:“Producer Extends, Consumer Super”(PECS)。
-
List extends Number>:能读Number及其子类(如Integer、Double),但不能add()(除了null),因为编译器不知道具体是哪种子类; -
List super Integer>:能安全add(Integer),但读出来只能当Object用,因为可能是List<number></number>或List<object></object>。
实际用法:方法参数该用哪个,取决于你是“往外取数据”还是“往里塞数据”。
泛型类、泛型方法、泛型接口怎么区分?
- 泛型类:类名后带
<t></t>,整个类的逻辑围绕这个类型展开,比如ArrayList<e></e>; - 泛型方法:方法签名前加
<t></t>,类型由调用时推断,比如public <t> void print(T item)</t>; - 泛型接口:接口定义带
<t></t>,实现类要么指定具体类型(class A implements Comparable<string></string>),要么自己也声明为泛型(class B<t> implements Comparable<t></t></t>)。
注意:静态方法不能直接访问类的泛型参数(因为类泛型在实例化时才确定),所以要用泛型方法形式声明自己的<t></t>。
不复杂但容易忽略。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










