Как найти перегруженный метод в 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
, а затем вызывает его.