Java泛型在运行时类型参数被擦除,但编译器插入类型转换并保留部分泛型信息;无法通过getClass()获取类型参数,但Method.getGenericReturnType()等可读取class文件中存储的签名字符串。

Java泛型在运行时真的“不存在”吗?
不是完全不存在,而是类型参数被擦除为上界(通常是 Object),但编译器会插入强制类型转换,并保留部分泛型信息用于编译期检查。比如 List 在字节码里是 List,但所有对 get() 的调用后都会紧跟一个 checkcast String 指令。
真正“消失”的是类型参数本身——你无法在运行时通过 list.getClass().getTypeParameters() 拿到 String;但像 Method.getGenericReturnType() 这类 API 仍能返回带泛型的 Type 对象,因为方法签名元数据在 class 文件中以字符串形式保留(如 Ljava/util/List)。
为什么 new ArrayList() 不能推导出 T 的实际类型?
因为构造器调用不参与类型推导上下文:泛型方法或泛型类的类型参数推导,依赖的是“目标类型”(target type)或“实参类型”(argument types),而 new 表达式本身没有目标类型约束(除非显式声明变量类型或作为方法参数传入)。
-
ArrayList→ 编译器从左侧list = new ArrayList(); ArrayList推出右侧的 -
foo(new ArrayList());→ 若foo声明为,则根据void foo(List x) ArrayList实现List的事实 + 类型擦除规则,T被推为Object(而非报错),因为擦除后只剩List -
new ArrayList() {{ add("a"); }};→ 依然推不出String,因为双大括号初始化创建的是匿名子类,其泛型信息不参与构造器推导
Class 和 TypeToken 怎么绕过类型擦除?
它们不真正“恢复”运行时类型,而是靠开发者手动把类型信息以对象形式带进来:Class 是运行时存在的具体类型载体;TypeToken(如 Gson 或 Guava 中的)利用匿名子类的 getGenericSuperclass() 在编译期捕获泛型签名,再解析出实际类型参数。
立即学习“Java免费学习笔记(深入)”;
new TypeToken>() {}.getType(); // 匿名子类的父类型签名含 "List
" 字符串
注意:这种技巧只对**带泛型的直接父类型**有效,一旦中间隔了桥接类、类型变量或通配符(如 ? extends Number),解析就会退化或失败。
媒体包提供了可管理各种媒体类型的类。这些类可提供用于执行音频和视频操作。除了基本操作之外,还可提供铃声管理、脸部识别以及音频路由控制。本文说明了音频和视频操作。 本文旨在针对希望简单了解Android编程的初学者而设计。本文将指导你逐步开发使用媒体(音频和视频)的应用程序。本文假定你已安装了可开发应用程序的Android和必要的工具,同时还假定你已熟悉Java或掌握面向对象的编程概念。感兴趣的朋友可以过来看看
常见坑:
- 传入
getClass()得到的是子类的Class,不是泛型声明类 ——new ArrayList返回().getClass() ArrayList.class,不是List(后者语法非法).class -
TypeToken必须是**匿名子类实例**,写成new TypeToken就失效(无泛型签名可读)- >().getType()
- 反射获取
Field.getGenericType()能拿到ParameterizedType,但字段必须是声明在当前类中,且不能是局部变量或形参
泛型数组创建为何必须用 Array.newInstance() 而非 new T[10]?
因为 T 在运行时已被擦除,new T[10] 编译不过(JVM 不允许创建泛型数组)。正确做法是用原始类型 + 反射构造,例如:
publicT[] createArray(Class clazz, int size) { return (T[]) Array.newInstance(clazz, size); }
这本质是“欺骗”类型系统:你提供 Class,它返回 String[],但返回值被强制转为 T[],触发 unchecked warning。若后续将该数组赋给 String[] 变量并存入非 String 对象,会在运行时抛 ArrayStoreException —— 这是 JVM 对数组协变性的运行时保护,和泛型擦除无关。
所以别试图用 (T[]) new Object[10],它在多态场景下极易引发 ClassCastException,因为数组实际类型是 Object[],不是 String[]。
TypeToken)其实高度依赖代码书写方式和继承结构,稍一变形就失效。









