我有这个奇怪的情况,我想通过反射或一些库来处理,如果可能的话。是否有一种方法来检查一个类是否有一个方法,然后在一个已经存在的对象实例上调用它?
例如,假设我有:
Foo foo = new Foo();
Foo
有close()
方法。假设我知道很多类都有一个close()
方法,但由于它们设计得很差,并且是我无法重写的遗产,我想找到一个通用的解决方案来调用我知道它们都有的方法,尽管它们不是继承自基类或接口。
我想有一个方法在我的FooHandling
类接受初始化的对象,并调用他们的close()
方法。这些对象绝不会从同一个基类继承,所以它们本质上是完全不同的,但都有一个具有相同名称的方法。因此,在FooHandler
中,我想要这样做:
void coolGenericClosingMethod(Object o)
{
// 1) Check via reflection if the class `o` represents contains a `close()`
// 2) Invoke the method, if it exists, but on the passed in object `o`.
}
那么,是否有一些巧妙的技巧,我可以在一个已经实例化的对象上使用,并且仍然这样做?
有没有办法检查一个类是否有一个方法
类# getMethods ()
返回一个包含Method对象的数组,该数组反映由这个class对象表示的类或接口的所有
public
成员方法,包括由类或接口声明的方法和继承自超类和超接口的方法
类# getMethod(字符串,类…)
返回一个Method对象,该对象反映由这个class对象表示的类或接口的指定公共成员方法。
name
参数为字符串,指定the desired method
的简单名称。
抛出:
NoSuchMethodException
-如果没有找到匹配的方法
示例代码:
class Foo {
public void close() {
System.out.println("close method is invoked");
}
}
Foo foo = new Foo();
try {
Method m = Foo.class.getMethod("close");
m.invoke(foo);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
输出:
close method is invoked
是的,你可以使用反射,就像这样
public static Object invokeIfExists(Object obj, String methodName,
Class<?>[] argTypes, Object[] args) throws IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
Method method = null;
Object result = null;
try {
method = obj.getClass().getMethod(methodName, argTypes);
} catch(NoSuchMethodException | SecurityException e) {
// method not available in class or a security constrain has denied access
// ignore or at least do some loggin
}
if(method != null) {
result = method.invoke(obj, args);
}
return result;
}
获取方法对象的方法是class# getMethod(String, Class…),它允许你使用它的签名(形式参数列表)找到你正在寻找的特定方法,所以在所有重载的方法中,你得到你需要的那个。
在所有抛出的异常中,你可能最感兴趣的是InvocationTargetException,它告诉你被调用的方法抛出了一个异常。
您可以做其他人已经回答过的问题,但是如果您不想过多地使用反射,也有一些现成的选项。例如Apache Commons BeanUtils:
import org.apache.commons.beanutils.MethodUtils;
...
try {
// 1st param: object reference
// 2nd param: method name
// 3rd param: args (null if no args)
MethodUtils.invoke(obj, "close", null);
} catch (NoSuchMethodException ex) {
// obj does not have a "close" method with no args
} catch (InvocatonTargetException ex) {
// obj.close() was called, and threw ex.getCause()
} catch (IllegalAccessException ex) {
// obj.close() exists, but you don't have permissions to invoke it
}
...
这些库也倾向于保持方法缓存,所以你得到快速反射;通过缓存,您可以跳过反射:方法查找的慢部分。