java泛型在编译期被擦除,运行时无法获取真实类型参数——这导致instanceof list编译失败、getclass()返回原始类型、不能new t[]或new t()、静态成员不可用泛型参数、基本类型不可作实参,所有限制均源于擦除后jvm仅见object或上界类型。

直接练核心场景,不堆概念。泛型面试真正卡人的,从来不是“什么是泛型”,而是你写不出、改不对、解释不清的那几类代码。
盯住三类高频真题动手写
别背定义,拿笔写——每类至少手敲 2 遍,边写边自问“这里为什么不能这么写”:
-
擦除导致的运行时失效题:写一个方法,传入
List<string></string>,尝试用instanceof List<string></string>判断,编译报错;再改成instanceof List,能过。接着打印list.getClass() == ArrayList.class,结果是true。这个过程必须亲手跑一遍。 -
泛型数组创建失败题:写
T[] arr = new T[5];,IDE 立刻红标;改成T[] arr = (T[]) new Object[5];,能编译但有警告。再补一句arr[0] = (T) "hello";,观察是否报错——这就是擦除后类型信息丢失的实感。 -
通配符边界混淆题:定义方法
void copy(List extends Number> src, List<number> dst)</number>,试着往dstadd(1.5f),成功;但往srcadd(1),编译失败。换用? super Integer,反过来验证读写限制。
重点练“不能做什么”背后的逻辑
面试官爱问“为什么不能……”,答案不在语法手册里,在擦除机制里:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 静态字段/方法不能用
T→ 因为擦除后所有泛型实例共享同一份字节码,static属于类,而T属于实例,二者生命周期冲突; - 不能
new T()→ 擦除后只剩Object,编译器无法确认构造函数是否存在; - 基本类型不能当泛型实参 →
int不是Object子类,而泛型底层全按引用类型处理,所以必须用Integer; -
getClass()拿不到泛型信息 → 运行时只剩原始类型,new ArrayList<string>().getClass()</string>和new ArrayList<integer>().getClass()</integer>完全一样。
用真实接口倒推泛型设计
打开 JDK 源码(如 java.util.List<e></e>、java.util.Comparator<t></t>),对照着写实现:
- 自己写一个
SimpleStack<t></t>,含push(T)、pop()、isEmpty(),注意泛型字段声明和返回值类型; - 再写一个
MaxFinder<t extends comparable>></t>,实现findMax(T[]),体会上界限定怎么约束类型行为; - 最后写个工具方法
<k v> Map<k v> of(K k, V v)</k></k>,理解方法级泛型如何独立于类泛型工作。
讲清楚一道题比背十道题有用
选一道你写过的题(比如“为什么 List<string></string> 不是 List<object></object> 的子类”),用两句话说清:
- Java 泛型是不变的(invariant),不是协变的;
- 如果允许,就能把
Integer放进本该只存String的容器,破坏类型安全——擦除虽在编译后抹掉类型,但编译期必须靠这套规则守住底线。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










