如何在Java中找到重载的方法?

2022-09-03 08:12:27

当写这样的东西

doit(43, 44, "hello");

编译器知道要调用哪个重载方法。当我想通过反思做同样的事情时,我需要自己发现,方法是

doit(Integer, double, CharSequence...);

并通过以下方式获取它

Class[] types = {Integer.class, double.class, CharSequence[].class};
declaringClass.getDeclaredMethod("doit", types);

我想知道是否已经有什么东西允许我写

Method m = getMethod(declaringClass, "doit", 43, 44, "hello");

我想知道是否有人已经这样做了,因为JLS在这方面有点复杂。


实际上,行为与编译器完全一样是不可能的,因为在阶段 1 中,编译器只接受匹配的方法,而不进行装箱和取消装箱。当从上面调用我的假设时,基元和它们的包装器之间的区别已经丢失了(因为在通过varargs传递参数时会自动装箱)。这个问题似乎没有解决方案,所以让我们忽略它。getMethod

正如答案中所建议的那样,接近。它应该找到最好的匹配,无论它意味着什么。查看MethodUtils可以看出BeanUtils.invokeMethod.getMatchingAccessibleMethod

  • 它对varargs一无所知
  • 它是非确定性的

所以我正在寻找更好的东西。


答案 1

或者,您可以使用Apache Commons中的Bean Utils

public static Method getAccessibleMethod(
        Class clazz,
        String methodName,
        Class[] parameterTypes)

根据文档

返回具有给定名称和参数的可访问方法(即,可通过反射调用的方法)。如果找不到此类方法,则返回 null。这只是getAccessibleMethod(方法方法)的一个方便的包装器。

参数:clazz - 从此类获取方法 methodName - 获取具有此名称参数的方法类型 - 具有这些参数类型

实现获取可访问的方法并在层次结构中向上移动,直到找到与它匹配的方法。

直接到调用

为了按照您的要求直接执行调用,您可以从同一个API中使用此方法:

public static Object invokeExactMethod(
        Object object,
        String methodName,
        Object[] args,
        Class[] parameterTypes)
        throws
        NoSuchMethodException,
        IllegalAccessException,
        InvocationTargetException

甚至

public static Object invokeExactMethod(
        Object object,
        String methodName,
        Object[] args)
        throws
        NoSuchMethodException,
        IllegalAccessException,
        InvocationTargetException

首先使用找到方法,然后调用它。getAccessibleMethod


答案 2

MethodHandle是一种使用签名(java 7)获取重载方法的新方法:

例:

static class A {
    public String get() {
        return "A";
    }
}

static class B extends A {
    public String get() {
        return "B";
    }
}

public static void main(String[] args) throws Throwable {

    MethodHandles.Lookup lookup = MethodHandles.lookup();
    MethodType mt = MethodType.methodType(String.class);
    MethodHandle mh = lookup.findVirtual(A.class, "get", mt);;

    System.out.println(mh.invoke(new B()));
}

输出:

B