有没有办法检查一个类是否有一个方法,然后在已经存在的对象实例上调用它?

时间:2014-07-21 18:26:23

标签: java reflection

我有这个奇怪的案例,如果可能的话,我想通过反思或某些图书馆处理。 有没有办法检查一个类是否有一个方法,然后在已经存在的对象实例上调用它?

例如,让我们说:

Foo foo = new Foo();

Fooclose()方法。让我们说我知道很多类都有一个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`.
}

那么我可以在已经实例化的对象上使用一些巧妙的技巧并仍然这样做吗?

3 个答案:

答案 0 :(得分:5)

  

有没有办法检查一个类是否有方法

Class#getMethods()

  

返回一个数组,其中包含反映此Class对象所代表的类或接口的所有public成员方法的Method对象,包括由类或接口声明的那些以及从超类和超接口继承的那些

Class#getMethod(String,Class...)

  

返回一个Method对象,该对象反映此Class对象所表示的类或接口的指定公共成员方法。 name参数是一个String,指定简单名称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

答案 1 :(得分:3)

是的你可以使用反射来做这样的事情

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,它告诉您调用的方法引发了异常。

答案 2 :(得分:0)

你可以做其他人已经回答过的事情,但是如果你不想用反射过多的话,有一些现成的选择。一个例子是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
}
...

这些库也倾向于保留方法缓存,因此您可以获得快速反射;通过缓存,您可以跳过反射的部分:方法查找。