根据java编译器规则在Class中搜索匹配指定参数类型表的泛型方法(GenericMethod)
来源:互联网 发布:陈浩民 妻子 知乎 编辑:程序博客网 时间:2024/06/16 00:14
因为项目的需要,设计了一个满足特定需要的代码自动生成工具。在开发过程中需要根据方法名和方法参数类型数组在指定的类中根据java编译器的规则找到与之最匹配的泛型方法。
例如,对下面这个类 ,调用test(1,new URL(“http://www.sohu.com“),new Date())会最终调用到哪个方法?
当然java器肯定知道,但它是用什么规则进行匹配的呢?
public class TestGenericMethod { public void test(String a,String b,byte[] c){ } public void test(Date a,URL b,byte[] c){ } public <T>void test(int a,URL b,T c){ } public <T1,T2,T3>void test(T1 a,T2 b,T3 c){ }}
于是对java关于泛型方法匹配的方式做了研究,发现java编译器在匹配泛型方法时,对参数的匹配是遵循从左到右的顺序来一个个检查的,根据这个规则写了下面的方法来实现泛型方法的精确匹配。
/** * @param clazz 要搜索的类 * @param name 方法名 * @param parameterTypes 希望匹配的参数类型数组 * @return * @throws NoSuchMethodException */ public static final java.lang.reflect.Method getGenericMethod(Class<?>clazz,String name,Class<?>... parameterTypes) throws NoSuchMethodException{ List<java.lang.reflect.Method> methods=new ArrayList<java.lang.reflect.Method>(); //查找同名且参数数目相同的所有方法 for (java.lang.reflect.Method m : clazz.getMethods()) if (m.getName().equals(name) && m.getParameterTypes().length == parameterTypes.length) methods.add(m); if (!methods.isEmpty()) { //过滤掉所有不能匹配的方法 for (int i = 0; i < parameterTypes.length; i++) { for (Iterator<java.lang.reflect.Method> it = methods.iterator(); it.hasNext();) { if (!isConvert(it.next().getParameterTypes()[i], parameterTypes[i])) it.remove(); } if (methods.size() <= 1)//找到唯一匹配的方法或没有匹配的方法就中止循环 break; } if (methods.size() > 1) { //如果还有多个方法满足条件,再过滤掉不能直接赋值的方法 for (int i = 0; i < parameterTypes.length; i++) { for (Iterator<java.lang.reflect.Method> it = methods.iterator(); it.hasNext();) { if (!isAssignable(it.next().getParameterTypes()[i], parameterTypes[i])) it.remove(); } if (methods.size() <= 1)//找到唯一匹配的方法或没有匹配的方法就中止循环 break; } } if (methods.size() == 1) return methods.iterator().next(); else if (methods.size() > 1){ //如果还有多个方法满足条件,再过滤掉类型不相等的方法 for (int i = 0; i < parameterTypes.length; i++) { for (Iterator<java.lang.reflect.Method> it = methods.iterator(); it.hasNext();) { if (it.next().getParameterTypes()[i]!= parameterTypes[i]) it.remove(); } if (methods.size() <= 1)//找到唯一匹配的方法或没有匹配的方法就中止循环 break; } if (methods.size() == 1) return methods.iterator().next(); else if (methods.size() > 1) throw new IllegalStateException("found more matched method"); } } //没有找到匹配的方法就抛出异常 throw new NoSuchMethodException(); } /** * from对象是否能转换成to * @param to * @param from * @return */ public static final boolean isConvert(Class<?> to, Class<?> from) { if (!isAssignable(to, from)){ if (to.isPrimitive() && PRIMITIVE_TYPE_MAP.get(to) == from) { return true; } return false; } return true; } /** * from对象能否则直接赋值给to * @param to * @param from * @return */ public static final boolean isAssignable(Class<?> to,Class<?>from){ if (from.isPrimitive()) { if (to != from && !to.isAssignableFrom(PRIMITIVE_TYPE_MAP.get(from))) return false; } else if (!to.isAssignableFrom(from)) return false; return true; } //primitive类型与对应Object类的映射表 private static final Map<Class<?>, Class<?>> PRIMITIVE_TYPE_MAP = new HashMap<Class<?>, Class<?>>() { private static final long serialVersionUID = 2638066380035384674L; { put(int.class, Integer.class); put(boolean.class, Boolean.class); put(byte.class, Byte.class); put(short.class, Short.class); put(char.class, Character.class); put(long.class, Long.class); put(float.class, Float.class); put(double.class, Double.class); } };
补充说明
细心严谨的读者可能会发现这里面的逻辑并不十分严谨,可能会出现返回并不匹配方法的结果,不过在我的应用场景中有别的措施做了保证,所以不会有问题,你可以根据自己需要再补充一些检查代码。
0 0
- 根据java编译器规则在Class中搜索匹配指定参数类型表的泛型方法(GenericMethod)
- 在SD卡中寻找指定类型文件的方法
- Creo二次开发:根据参数在指定文件夹中查找模型
- 跳过编译器,获取泛型参数的实际类型
- Spring的Controller请求方法中参数名匹配,但是参数类型不同会报404
- Java中重载的匹配规则
- [Shell]在一个目录及其子目录内的指定类型的文件中搜索某个字符串
- GenericMethod java泛型
- C#中params 关键字可以指定在参数数目可变处采用参数的方法参数
- Java递归搜索指定文件夹下的匹配文件
- Java递归搜索指定文件夹下的匹配文件
- Java递归搜索指定文件夹下的匹配文件
- Java递归搜索指定文件夹下的匹配文件
- Java递归搜索指定文件夹下的匹配文件
- Java递归搜索指定文件夹下的匹配文件
- Java递归搜索指定文件夹下的匹配文件
- Java获取泛型参数的类型的方法
- Java获取泛型参数的类型的方法 .
- 自定义文件上传按钮
- iOS 的 Tint Color 属性详解
- 《 归·期》
- iOS学习之UISwitch控件两种使用方法和监听
- 第二天-关键字、控制语句
- 根据java编译器规则在Class中搜索匹配指定参数类型表的泛型方法(GenericMethod)
- mysql和eclipse都设置了utf8编码,保存时中文依然乱码
- jQuery("#").autocomplete 出现Status Code:404 Not Found
- Java 设计模式——工场模式(Factory method)
- iOS设计模式——委托(delegate)
- meta标签之viewport
- Objective-C入门18:KVO
- listView使用的万能的BaseAdapter
- UIKit框架的介绍