Как найти перегруженный метод в Java?

При написании чего-то типа

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 в этом отношении немного сложнее.


Собственно, поведение точно так же, как и компилятор, невозможно, так как в Phase 1 компилятор принимает только методы, соответствующие без бокса и распаковки. При вызове моего гипотетического getMethod сверху различие между примитивами и их оболочками уже потеряно (из-за автобоксинга при передаче аргументов через varargs). Эта проблема, похоже, не имеет решения, поэтому пусть игнорирует ее.

Как было предложено в ответе, BeanUtils.invokeMethod приближается. Он должен найти лучший матч, что бы это ни значило. Глядя на MethodUtils .getMatchingAccessibleMethod показывает, что

  • он ничего не знает о varargs
  • он не детерминирован

поэтому я ищу что-то лучшее.

Ответы

Ответ 1

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

Ответ 2

В качестве альтернативы вы можете использовать Bean Utils из Apache Commons:

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

В соответствии с документацией:

Возвращает доступный метод (то есть тот, который может быть вызван через отражение) с заданным именем и параметрами. Если такой метод не может быть found, return null. Это просто удобная обертка для getAccessibleMethod (метод метода).

Параметры: clazz - получить метод из этого класса methodName - получите метод с этим именем parametersTypes - с этими типами параметров

Реализация получает доступный метод и поднимается в иерархии, пока не найдет совпадение с ней.

Прямо к вызову

Чтобы выполнить вызов напрямую, как вы просили, вы можете использовать этот метод из того же 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, а затем вызывает его.