Использование java.lang.reflect.getMethod с полиморфными методами - PullRequest
8 голосов
/ 21 июня 2010

Рассмотрим следующий фрагмент:

public class ReflectionTest {

    public static void main(String[] args) {

        ReflectionTest test = new ReflectionTest();
        String object = new String("Hello!");

        // 1. String is accepted as an Object
        test.print(object);

        // 2. The appropriate method is not found with String.class
        try {
            java.lang.reflect.Method print
                = test.getClass().getMethod("print", object.getClass());
            print.invoke(test, object);
        } catch (Exception ex) {
            ex.printStackTrace(); // NoSuchMethodException!
        }
    }

    public void print(Object object) {
        System.out.println(object.toString());
    }

}

getMethod(), очевидно, не знает, что String может быть передан методу, который ожидает Object (действительно, в документации сказано, что он ищет метод с указанным именем и точно таким же формальным параметром типы ).

Существует ли простой способ рефлексивного поиска методов, как это делает getMethod(), но с учетом полиморфизма, чтобы приведенный выше пример отражения мог найти метод print(Object) при запросе параметров ("print", String.class)?

Ответы [ 3 ]

8 голосов
/ 21 июня 2010

Учебник по отражению

предлагают использовать Class.isAssignableFrom() образец для поиска print(String)

    Method[] allMethods = c.getDeclaredMethods();
    for (Method m : allMethods) {
        String mname = m.getName();
        if (!mname.startsWith("print") {
            continue;
        }
        Type[] pType = m.getGenericParameterTypes();
        if ((pType.length != 1)
            || !String.class.isAssignableFrom(pType[0].getClass())) {
            continue;
        }
     }
1 голос
/ 01 августа 2015

К вашему сведению, это способ вызова метода с использованием отражения с несколькими параметрами без указания их типов.

public class MyMethodUtils {
    /**
     * Need to pass parameter classes
     */
    public static Object invoke(Object invoker, String methodName, Object[] parameters, Class[] parameterClasses) throws Exception {
        Method method = invoker.getClass().getMethod(methodName, parameterClasses);
        Object returnValue = method.invoke(invoker, parameters);
        return returnValue;
    }

    /**
     * No need to pass parameter classes
     */
    public static Object invoke(Object invoker, String methodName, Object[] parameters) throws Exception {
        Method[] allMethods = invoker.getClass().getDeclaredMethods();
        Object returnValue = null;
        boolean isFound = false;
        for (Method m : allMethods) {
            String mname = m.getName();
            if (!mname.equals(methodName)) {
                continue;
            }
            Class[] methodParaClasses = m.getParameterTypes();
            for (int i = 0; i < methodParaClasses.length; i++) {
                Class<?> parameterClass = parameters[i].getClass();
                Class<?> methodParaClass = methodParaClasses[i];
                boolean isAssignable = methodParaClass.isAssignableFrom(parameterClass);
                if (!isAssignable) {
                    continue;
                }
            }
            returnValue = m.invoke(invoker, parameters);
            isFound = true;
        }
        if (!isFound) {
            throw new RuntimeException("Cannot find such method");
        }

        return returnValue;
    }

}

Пример использования:

    MyMethodUtils.invoke(student, "setNameAndMarks", new Object[] { "John", marks }, new Class[] { String.class, Collection.class });
    MyMethodUtils.invoke(student, "setNameAndMarks", new Object[] { "John", marks });

Однако для метода invoke(Object invoker, String methodName, Object[] parameters) можно вызвать неправильный метод, если сигнатура неоднозначна. Например, если есть два метода для invoker:

public void setNameAndMarks(String name, Collection<Integer> marks);
public void setNameAndMarks(String name, ArrayList<Integer> marks);

Передача следующего параметра может вызвать неправильный метод

setNameAndMarks("John", new ArrayList<Integer>());
1 голос
/ 23 июня 2010

Простой способ сделать это - через java.beans.Statement или java.beans.Expression. Делает все эти трудные дворы для вас.

getMethod () явно не знает, что Строка может быть передана методу ожидающий Объект

«Незнающий» - странный способ выразить это. getMethod() придерживается своей спецификации. Вы должны предоставить формальные параметры, а не типы фактических аргументов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...