Java泛型擦除不可绕过,但可通过Class参数传递、TypeToken保留签名、通配符边界、泛型方法+工厂模式等方式适配运行时需求。

Java 泛型擦除本身不可绕过,它是 JVM 兼容性设计的基石。但很多“限制”其实可以通过合理模式规避,关键不是阻止擦除,而是提前适配擦除后的运行时现实。
用 Class 显式传递类型信息
当需要在运行时知道具体类型(比如反序列化、泛型数组创建、类型检查),不能依赖 T 本身,而应把 Class<t></t> 作为参数传入:
-
public <T> T fromJson(String json, Class<T> clazz)—— Gson/ Jackson 都这样用 public <T> T[] newArray(Class<T> clazz, int size) { return (T[]) Array.newInstance(clazz, size); }- 避免写
new T[10],它编译失败;改用带Class的工厂方法
用 TypeToken 保留泛型签名
当需要获取带参数的完整类型(如 List<User>),可借助 Guava 的 TypeToken 或自定义匿名子类技巧:
-
new TypeToken<List<User>>() {}—— 利用匿名子类在字节码中保留泛型父类签名 - 再通过
.getType()获取ParameterizedType,配合反射提取实际类型参数 - 注意:仅对**直接继承声明**有效(如 extends ArrayList<String>),对局部变量无效
用通配符 + 边界替代硬编码泛型类型
避免因擦除导致重载冲突或 instanceof 失效:
立即学习“Java免费学习笔记(深入)”;
- 不用
void handle(List<String>)和void handle(List<Integer>)(擦除后都是List,编译报错) - 改用语义区分:
void handleStrings(List<? extends CharSequence>)、void handleNumbers(List<? extends Number>) - instanceof 检查写成
list instanceof List<?>,再结合元素getClass()做二次判断(谨慎使用)
用泛型方法+桥接逻辑替代泛型异常或数组
某些场景 Java 禁止泛型类型出现在特定位置(如 catch (MyError<T> e) 或 T[]),需换思路:
- 异常类不要带泛型:定义
class MyError extends Exception,把类型相关数据放进字段(如private final Class<?> payloadType) - 数组需求优先用
ArrayList<T>;若必须数组,用Object[]+ 显式转型,并接受@SuppressWarnings("unchecked")(确保调用方安全) - 泛型方法中需构造对象时,不写
new T(),改用Supplier<T>或工厂接口传入


















