练好Java泛型关键在于理解擦除机制、动手验证与对比差异:通过getClass()验证运行时类型相同,反射对比getGenericType()与getType(),实例化泛型数组和instanceof T报错等实践深化认知。

练好Java泛型面试题,关键不是死记答案,而是理解机制、动手验证、对比差异。下面几个方向最有效:
从擦除机制反推行为
泛型的“运行时不存在”是几乎所有难点的根源。练的时候别只背结论,要自己写代码验证:
- 写一个
List<String>和一个List<Integer>,用getClass()打印它们的运行时类——结果都是ArrayList - 尝试用反射获取
field.getGenericType()(比如字段声明为private List<Date> dates;),再和field.getType()对比,体会“泛型信息只在声明处保留” - 写个方法
public static <T> void test(T t) { System.out.println(t instanceof String); }——编译直接报错,因为T擦除后是Object,无法做instanceof判断
用通配符解决真实传参问题
面试常考“为什么 List<String> 不是 List<Object> 的子类型”,练法就是写实际会出错的场景:
- 定义方法
void process(List<Number> list),然后传入ArrayList<Integer>——编译失败;改成void process(List<? extends Number> list)就能通过 - 写一个添加元素的方法
void addOne(List<? super Integer> list),试试能否往里加new Integer(1)或new Long(2),理解下界的作用边界 - 对比
<?>、<? extends T>、<? super T>在读/写操作上的限制,画个表格总结(比如“上界可读不可写,下界可写不可读”)
动手改写经典工具类
光看 Box<T> 示例太单薄。挑 JDK 里真实用到泛型的地方,自己重写简化版:
立即学习“Java免费学习笔记(深入)”;
- 手写一个
Pair<K, V>,带getKey()/getValue(),再写个public static <K, V> Pair<K, V> of(K k, V v)工厂方法 - 模仿
Optional<T>:实现of()、empty()、isPresent()、get(),注意get()抛异常时不能 throw T - 写个泛型单例容器
GenericHolder<T>,里面存一个static final Map<Class<?>, Object>,用Class<T>当 key 存取不同类型的实例——这是绕过擦除的常用技巧
故意写错再分析报错
很多知识点只有踩过坑才真正记住。专门写几段“看起来合理但编译不过”的代码:
-
T[] arr = new T[10];→ 报错:Cannot create a generic array -
if (t instanceof T)→ 报错:Illegal generic type for instanceof -
class A<T> implements Comparable<T>+class B extends A<String>→ 编译通过;但改成class B extends A<String> implements Comparable<B>就可能冲突,理解桥方法生成逻辑
不复杂但容易忽略:每次练习后,用 javap -c 看字节码,确认泛型是否真被擦除、桥方法是否存在——眼见为实。


















