结合Java泛型和反射来避免强制转换

时间:2011-05-06 17:38:04

标签: java generics reflection casting

我有一些像这样的代码:

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,我想{{1}足够聪明,将其返回类型更改为doMethod。有没有办法使用Java泛型来完成这样的事情?

String

3 个答案:

答案 0 :(得分:4)

当然,

@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);
}

演员将是你试图分配给它的任何东西,但我认为大多数人会认为它是可疑的。

答案 1 :(得分:3)

我希望Method已被参数化以捕获返回类型。您可以通过使用自己的MethodEx包装Method来自己做到这一点......这样做可以让您提供一些非常漂亮的外观......

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上使用工厂方法进行大量的前期验证,以确保方法是公开的等等。

最后,如果你正在缓存Method实例等并处理动态加载的类,这也是一个很好的机会来防御性地引入弱引用(对于方法和返回类型),所以你不必像小心在整个代码中挂起整个类加载器。

答案 2 :(得分:1)

你可以尝试

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

虽然它会将演员阵容移动到例程本身。一般来说,你想要做的事情听起来并不是一个好习惯。反思本身会产生一些性能开销,但也许不值得关注?