前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >根据java编译器规则在Class中搜索匹配指定参数类型表的泛型方法(GenericMethod)

根据java编译器规则在Class中搜索匹配指定参数类型表的泛型方法(GenericMethod)

作者头像
10km
发布2022-05-07 09:56:14
1.6K0
发布2022-05-07 09:56:14
举报
文章被收录于专栏:10km的专栏

因为项目的需要,设计了一个满足特定需要的代码自动生成工具。在开发过程中需要根据方法名和方法参数类型数组在指定的类中根据java编译器的规则找到与之最匹配的泛型方法。 例如,对下面这个类 ,调用test(1,new URL(“http://www.sohu.com“),new Date())会最终调用到哪个方法? 当然java器肯定知道,但它是用什么规则进行匹配的呢?

代码语言:javascript
复制
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编译器在匹配泛型方法时,对参数的匹配是遵循从左到右的顺序来一个个检查的,根据这个规则写了下面的方法来实现泛型方法的精确匹配。

代码语言:javascript
复制
    /**
     * @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);
        }
    };

补充说明 细心严谨的读者可能会发现这里面的逻辑并不十分严谨,可能会出现返回并不匹配方法的结果,不过在我的应用场景中有别的措施做了保证,所以不会有问题,你可以根据自己需要再补充一些检查代码。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2015-09-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档