Java泛型是编译期特性,运行时被类型擦除,getClass() 返回原始类型而非带泛型的类型;instanceof 检查泛型失败,反射仅可获取声明处的泛型信息,无法用于运行时类型判断或分支逻辑。

Java泛型不是运行时类型,getClass() 看不到泛型信息
Java泛型是编译期特性,擦除后只剩原始类型。你写 List<string></string>,运行时 list.getClass() 返回的是 ArrayList.class,不是 List<string>.class</string>——后者根本不存在。这是因为泛型信息在字节码里被擦除了。
常见错误现象:if (obj instanceof List<string>)</string> 编译不通过;new ArrayList<string>().getClass() == new ArrayList<integer>().getClass()</integer></string> 结果为 true。
- 想判断泛型实际类型?不行,得靠额外字段(如
TypeReference)或运行时传入Class<t></t> - 反射获取泛型参数?用
Field.getGenericType()或Method.getGenericReturnType(),但仅限于声明处的静态类型,不是实例值 - 不要试图用泛型做运行时分支逻辑,比如
if (T == String.class)—— T 在运行时已不存在
泛型方法和通配符的区别:什么时候该用 extends T>,什么时候该用 <t></t>
泛型方法声明(<T> void foo(T t))让调用方决定类型;通配符(List<? extends Number>)用于接收不确定子类型的集合,但限制写入。
使用场景差异明显:
立即学习“Java免费学习笔记(深入)”;
- 要往集合里 add 元素?用泛型方法或原始类型,别用
? extends——list.add(new Integer(1))在List<? extends Number>上会编译失败 - 只读遍历且接受多种子类?
? extends Number更安全,比如处理List<Integer>和List<Double>的统一接口 -
? super T适合消费场景,比如Collection<? super String>可以接收Object类型的集合,且允许 addString
泛型数组创建报错 Generic array creation 怎么绕过
Java 不允许直接创建泛型数组,比如 new List<string>[10]</string> 会触发编译错误 Generic array creation。原因还是类型擦除:JVM 需要在运行时知道数组元素类型,而 List<string></string> 擦除后只剩 List,无法构造类型安全的数组。
实操建议:
- 用
ArrayList替代数组:它内部用Object[]+ 强制转型,由泛型约束保证逻辑安全 - 真要数组?先建原始类型数组,再强制转型(带
@SuppressWarnings("unchecked")),例如:List<string>[] arr = (List<string>[]) new List[10];</string></string> - 更稳妥的做法:用
Arrays.asList()或Stream.toArray()配合构造器引用,避免手动管理泛型数组
泛型类继承时,子类要不要重写类型参数
子类是否保留泛型,取决于它是否需要复用父类的类型变量,还是固定某个具体类型。
容易踩的坑:
- 父类是
class Box<t></t>,子类写成class StringBox extends Box<string></string>—— 这没问题,但子类不再是泛型类,不能被进一步参数化 - 如果子类也要支持任意类型,得声明为
class GenericBox<t> extends Box<t></t></t>,否则T无法传递下去 - 注意桥接方法(bridge method):当子类覆盖泛型父类方法时,编译器可能生成合成方法,调试时看到多出的方法名别慌,那是为了兼容擦除后的调用协议
泛型真正难的地方不在语法,而在理解“擦除”带来的边界感——它既给你编译期安全,又不让你在运行时依赖它。多数问题,其实都是忘了这一点。









