Объединение обобщений Java и рефлексии, чтобы избежать приведения - PullRequest
3 голосов
/ 06 мая 2011

У меня есть такой код:

Object doMethod(Method m, Object... args) throws Exception {
    Object obj = m.getDeclaringClass().getConstructor().newInstance();
    return m.invoke(obj, args);
}

Код, который я использую, немного сложнее, но в этом-то и заключается идея.Для вызова doMethod я делаю что-то вроде этого:

Method m = MyClass.class.getMethod("myMethod", String.class);
String result = (String)doMethod(m, "Hello");

Это прекрасно работает для меня (переменное число аргументов и все). То, что меня раздражает, - это необходимая приведение к String в вызывающей стороне. Поскольку myMethod объявляет, что возвращает String, я бы хотел, чтобы doMethod был достаточно умен, чтобы изменить его.тип возврата также должен быть String.Есть ли какой-нибудь способ использования обобщений Java для достижения чего-то подобного?

String result = doMethod(m, "Hello");
int result2 = doMethod(m2, "other", "args");

Ответы [ 3 ]

4 голосов
/ 06 мая 2011

Конечно,

@SuppressWarnings("unchecked")
<T> T doMethod(Method m, Class<T> returnType, Object Args ...) {
    Object obj = m.getDeclaringClass().getConstructor().newInstance();
    return (T) m.invoke(obj, args);
}

String result = doMethod(m, m.getReturnType(), "Hello");

Одному безразлично, какая архитектура требует такой вещи, но это выходит за рамки :))

Если вам это не нравится, вы также можете отключить привязку returnType, и компилятор автоматически приведёт его к тому типу, которому вы назначаете тип возврата. например, это законно:

@SuppressWarnings("unchecked")
<T> T doMethod(Method m, Object Args ...) {
    Object obj = m.getDeclaringClass().getConstructor().newInstance();
    return (T) m.invoke(obj, args);
}

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

3 голосов
/ 06 мая 2011

Хотелось бы, чтобы метод был параметризован для захвата возвращаемого типа.Вы всегда можете сделать это самостоятельно, обернув Method своим собственным MethodEx ... Это позволит вам также предоставить некоторые довольно красивые фасады ...

public class MethodEx<T> {
  private final Method _method;
  private final Class<T> _returnType;

  public MethodEx(Method method, Class<T> returnType) {
    _method = method;
    _returnType = returnType;
  }

  public T invoke(Object object, Object... args) throws InvocationTargetException {
    try {
      return _returnType.cast(_method.invoke(object, args));
    }
    // good opportunity to hide/wrap other exceptions if your 
    // usecases don't really encounter them
  }
}

Это только отправная точка - вы можетеиметь фабричные методы для MethodEx, которые выполняют предварительную проверку, чтобы убедиться, что метод общедоступен и т. д.

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

1 голос
/ 06 мая 2011

Вы можете попробовать

public <T> T doMethod(Method m, Class<T> clazz, Object... args);

Хотя он перемещает актерский состав к самой процедуре. В целом то, что вы пытаетесь сделать, не похоже на хорошую практику. Отражение само по себе влечет за собой некоторое снижение производительности, но, может быть, это не имеет значения?

...