java – 反射性地检查对象是否是方法的有效泛型参数
如何使用反射检查给定对象是否是方法的有效参数(参数和对象是泛型类型)?
为了获得一些背景知识,这就是我想要实现的目标: 在使用反射方法调用时,我认为调用具有特定类型参数的所有方法会很好.这适用于原始类型,因为您可以在其类对象上调用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>()); } } 会打印 You called me! You called me again! 无论T看起来如何(即它可能是另一个通用类型,例如List< List< Integer>>),这应该是可能的. 显然这不起作用,因为类型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,List<T> number) { return method.getGenericParameterTypes()[0].equals(number.getClass().getGenericSuperclass()); } public static void main(String[] args) { reflectiveCall(new ArrayList<Integer>(){}); } } 只打印 You called me! 但是,这有一些额外的警告: >它仅适用于直接实例,并且不考虑继承层次结构,因为Type接口不提供所需的方法.这里和那里的演员肯定有助于找到这一点(另见我的第二次尝试) 尝试2 考虑到由于擦除而在理想解决方案中缺失类型,人们也可以将该类型作为一个非常接近理想的参数传递: 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,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); } } 实际上打印正确的解决方案.但这也不是没有消极方面: > reflectCall的用户需要传递类型参数,这是不必要和繁琐的.至少在编译时检查正确的调用. 这个问题 有什么我可以做的不同,以尽可能接近我的目标?我是坚持使用匿名子类还是传递类型参数?目前,我将决定给出参数,因为这样可以节省编译时间. 在递归检查参数类型时,我需要注意什么? 是否有可能允许泛型在解决方案2中使用类型参数? 实际上,出于学习目的,我想推出自己的解决方案而不是使用库,尽管我不介意看一些内部工作. 为了清楚起见,我举例说明了以下内容,但尝试保持示例清洁: >这可以在没有反射的情况下解决(同时重新设计一些要求并使用例如接口和内部类).这是出于学习目的.我想要解决的问题实际上要大得多,但这就是它归结为什么. 解决方法
或多或少,但更好地使用super type token模式子类而不是子类化您的值类型.毕竟,您的值类型可能不允许子类.使用类型标记模式允许您接受泛型类型,而接受类作为类型参数仅允许原始类型(这就是您必须采用List的组件类型而不是类型本身的原因). public static <T> void reflectiveCall(TypeToken<T> type,T value) Guava非常支持创建和使用 reflectiveCall(new TypeToken<List<Integer>>() {},new ArrayList<Integer>()); 一旦你有了这个,canBeParameterOf变得更容易实现. public static boolean canBeParameterOf(Method method,TypeToken<?> givenType) { Type[] argTypes = method.getGenericParameterTypes(); return argTypes.length != 0 && TypeToken.of(argTypes[0]).isAssignableFrom(givenType); } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- performance – 在四元组的向量中取消装箱的盒装值
- java – 多租户应用程序的数据源
- springboot+thymeleaf国际化之LocaleResolver接口的示例
- java基数排序算法
- java-1.7.0-openjdk-i386和java-7-openjdk-i386有什么区别
- ogn1.MethodFailedException:Method "xxx" fail
- java – 涉及Swing和AWT-EventQueue的无响应线程
- java – 以编程方式插入行(父级和子级)
- Elastic Search Java Api 创建索引结构,添加索引
- java – 将所有键从LinkedHashMap提取到列表的方法