Java 反射式检查对象是否是方法的有效泛型参数
如何使用反射检查给定对象是否是方法的有效参数(其中参数和对象是泛型类型) 为了了解一些背景知识,我正试图实现以下目标: 在处理反射方法调用时,我认为最好调用所有具有特定类型参数的方法。这适用于原始类型,因为您可以在其类对象上调用Java 反射式检查对象是否是方法的有效泛型参数,java,generics,reflection,type-erasure,Java,Generics,Reflection,Type Erasure,如何使用反射检查给定对象是否是方法的有效参数(其中参数和对象是泛型类型) 为了了解一些背景知识,我正试图实现以下目标: 在处理反射方法调用时,我认为最好调用所有具有特定类型参数的方法。这适用于原始类型,因为您可以在其类对象上调用isAssignableFrom(Class c)。然而,当你开始在混合中加入泛型时,它突然变得不那么容易了,因为泛型不是反射最初设计的一部分,而且是因为类型擦除 问题更大,但基本上归结为以下几点: 理想溶液 理想情况下,代码 import java.lang.refle
isAssignableFrom(Class c)
。然而,当你开始在混合中加入泛型时,它突然变得不那么容易了,因为泛型不是反射最初设计的一部分,而且是因为类型擦除
问题更大,但基本上归结为以下几点:
理想溶液
理想情况下,代码
import java.lang.reflect.*;
import java.util.*;
public class ReflectionAbuse {
public static void callMeMaybe(List<Integer> number) {
System.out.println("You called me!");
}
public static void callMeAgain(List<? extends Number> number) {
System.out.println("You called me again!");
}
public static void callMeNot(List<Double> number) {
System.out.println("What's wrong with you?");
}
public static <T> void reflectiveCall(List<T> number){
for(Method method : ReflectionAbuse.class.getDeclaredMethods()) {
if(method.getName().startsWith("call")) {
if(canBeParameterOf(method, number)) {
try {
method.invoke(null, number);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
public static <T> boolean canBeParameterOf(Method method, List<T> number) {
// FIXME some checks missing
return true;
}
public static void main(String[] args) {
reflectiveCall(new ArrayList<Integer>());
}
}
无论T
看起来如何,这都应该是可能的(即,它可能是另一种泛型类型,例如List
)
显然,这无法工作,因为类型t
在运行时被擦除且未知
尝试1
我能做的第一件事就是这样:
import java.lang.reflect.*;
import java.util.*;
public class ReflectionAbuse {
public static void callMeMaybe(ArrayList<Integer> number) {
System.out.println("You called me!");
}
public static void callMeAgain(ArrayList<? extends Number> number) {
System.out.println("You called me again!");
}
public static void callMeNot(ArrayList<Double> number) {
System.out.println("What's wrong with you?");
}
public static <T> void reflectiveCall(List<T> number){
for(Method method : ReflectionAbuse.class.getDeclaredMethods()) {
if(method.getName().startsWith("call")) {
if(canBeParameterOf(method, number)) {
try {
method.invoke(null, number);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
public static <T> boolean canBeParameterOf(Method method, List<T> number) {
return method.getGenericParameterTypes()[0].equals(number.getClass().getGenericSuperclass());
}
public static void main(String[] args) {
reflectiveCall(new ArrayList<Integer>(){});
}
}
但是,这还有一些额外的注意事项:
- 它只适用于直接实例,继承层次结构不被考虑,因为
接口没有提供所需的方法。这里和那里的演员阵容肯定会有助于找到答案(另请参见我的第二次尝试)类型
的参数实际上需要是所需参数类型的子类(注意reflectiveCall
中创建匿名内部类的newarraylist(){}
)。这显然不太理想:创建不必要的类对象,并且容易出错。这是我唯一能想到的绕过类型擦除的方法{}
import java.lang.reflect.*;
import java.util.*;
public class ReflectionAbuse {
public static void callMeMaybe(List<Integer> number) {
System.out.println("You called me!");
}
public static void callMeAgain(List<? extends Number> number) {
System.out.println("You called me again!");
}
public static void callMeNot(List<Double> number) {
System.out.println("What's wrong with you?");
}
public static <T> void reflectiveCall(List<T> number, Class<T> clazz){
for(Method method : ReflectionAbuse.class.getDeclaredMethods()) {
if(method.getName().startsWith("call")) {
Type n = number.getClass().getGenericSuperclass();
if(canBeParameterOf(method, clazz)) {
try {
method.invoke(null, number);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
public static <T> boolean canBeParameterOf(Method method, Class<T> clazz) {
Type type = ((ParameterizedType)method.getGenericParameterTypes()[0]).getActualTypeArguments()[0];
if (type instanceof WildcardType) {
return ((Class<?>)(((WildcardType) type).getUpperBounds()[0])).isAssignableFrom(clazz);
}
return ((Class<?>)type).isAssignableFrom(clazz);
}
public static void main(String[] args) {
reflectiveCall(new ArrayList<Integer>(), Integer.class);
}
}
import java.lang.reflect.*;
导入java.util.*;
公共类反射总线{
公共静态无效callMeMaybe(列表编号){
System.out.println(“你叫我!”);
}
公共静态无效呼叫增益(列表
我是不是一直在使用匿名子类还是传递类型参数
或多或少,但最好使用该模式进行子类化,而不是对您的值类型进行子类化。毕竟,您的值类型可能不允许子类。使用类型标记模式允许您接受泛型类型,而接受类
作为类型参数只允许原始类型(这就是为什么必须采用列表的组件类型,而不是类型本身)
一旦你有了这个,canBeParameterOf
就更容易实现了
public static boolean canBeParameterOf(Method method, TypeToken<?> givenType) {
Type[] argTypes = method.getGenericParameterTypes();
return argTypes.length != 0 &&
TypeToken.of(argTypes[0]).isAssignableFrom(givenType);
}
public静态布尔值canBeParameterOf(方法,TypeToken给定类型){
类型[]argTypes=method.getGenericParameterTypes();
返回argTypes.length!=0&&
(argTypes[0])的TypeToken.isAssignableFrom(givenType);
}
相关:
import java.lang.reflect.*;
import java.util.*;
public class ReflectionAbuse {
public static void callMeMaybe(List<Integer> number) {
System.out.println("You called me!");
}
public static void callMeAgain(List<? extends Number> number) {
System.out.println("You called me again!");
}
public static void callMeNot(List<Double> number) {
System.out.println("What's wrong with you?");
}
public static <T> void reflectiveCall(List<T> number, Class<T> clazz){
for(Method method : ReflectionAbuse.class.getDeclaredMethods()) {
if(method.getName().startsWith("call")) {
Type n = number.getClass().getGenericSuperclass();
if(canBeParameterOf(method, clazz)) {
try {
method.invoke(null, number);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
public static <T> boolean canBeParameterOf(Method method, Class<T> clazz) {
Type type = ((ParameterizedType)method.getGenericParameterTypes()[0]).getActualTypeArguments()[0];
if (type instanceof WildcardType) {
return ((Class<?>)(((WildcardType) type).getUpperBounds()[0])).isAssignableFrom(clazz);
}
return ((Class<?>)type).isAssignableFrom(clazz);
}
public static void main(String[] args) {
reflectiveCall(new ArrayList<Integer>(), Integer.class);
}
}
public static <T> void reflectiveCall(TypeToken<T> type, T value)
reflectiveCall(new TypeToken<List<Integer>>() {}, new ArrayList<Integer>());
public static boolean canBeParameterOf(Method method, TypeToken<?> givenType) {
Type[] argTypes = method.getGenericParameterTypes();
return argTypes.length != 0 &&
TypeToken.of(argTypes[0]).isAssignableFrom(givenType);
}