跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

如何描述 Java 泛型中的类型擦除对反射调用 invoke 时参数匹配的影响

Java泛型类型擦除导致反射invoke只能按原始类型匹配参数,无法基于泛型精确匹配;需用getGenericParameterTypes()获取真实泛型信息,注意桥接方法干扰。 Java 泛型的类型擦除会直接影响反射调用
invoke
时的参数匹配逻辑——不是因为泛型本身“干扰”了方法查找,而是因为擦除后的方法签名在字节码中已不包含泛型信息,导致反射无法基于泛型参数做精确匹配,只能按原始类型(raw type)匹配。 方法签名在运行时只剩原始类型 泛型方法或泛型类中的方法,在编译后其参数和返回值类型均被擦除为边界类型(无界则为
Object
)。例如:
public void process(List data)
→ 擦除为
public void process(List data)
public T parse(String s)
→ 擦除为
public Number parse(String s)
反射调用
Method.invoke(obj, args...)
时,
Method
对象是通过
Class.getMethod()
或
getDeclaredMethod()
获取的,而这些方法**只认擦除后的签名**。你传入
ArrayList
,反射底层看到的只是
ArrayList
;传入
Integer
,它只当它是
Object
或其上界类型。 参数类型检查完全失效 编译期的泛型约束在运行时不生效,所以反射可以绕过所有类型限制: Eclipse导入Android或其他的JAVA项目的正确方法 WORD版 本文档主要讲述的是Eclipse导入Android或其他的JAVA项目的正确方法;希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看 下载 立即学习 “ Java免费学习笔记(深入) ”; 一个声明为
void add(Integer x)
的泛型方法(如在
Box
中),擦除后实际是
void add(Object x)
用反射调用时,传入
"hello"
(
String
)也能成功,不会抛
IllegalArgumentException
这和直接调用不同:编译器会对
box.add("hello")
报错,但反射跳过了编译检查 获取泛型参数信息需额外手段 若你想在反射中还原真实泛型参数(比如做类型校验或自动转换),不能依赖
method.getParameterTypes()
(它返回的是擦除后的
Class[]
),而要改用:
method.getGenericParameterTypes()
返回
Type[]
,其中可能是
ParameterizedType
对
ParameterizedType
调用
getActualTypeArguments()
才能拿到
String.class
、
Integer.class
等实参 注意:该信息仅保留在方法声明处(如字段、方法签名、父类继承关系中),运行时对象实例本身不携带泛型参数 桥接方法可能干扰 method 查找 泛型类重写父类方法时,编译器会生成桥接方法(bridge method),它和原始方法共存于字节码中。例如:
class Child extends Parent
重写了
set(T t)
会生成一个桥接方法
set(Object o)
,再委托给擦除后的
set(String s)
用
getDeclaredMethod("set", Object.class)
可能拿到桥接方法而非你预期的泛型方法,影响参数处理逻辑 建议用
getMethods()
配合
isBridge()
过滤,或优先用
getGenericParameterTypes()
判断语义意图

相关文章