简体   繁体   中英

Is there a way to check if a class has a method and then invoke it on an already existing instance of the object?

I have this odd case which I'd like to handle through reflection or some library, if possible. Is there a way to check if a class has a method and then invoke it on an already existing instance of the object?

For example, let's say I have:

Foo foo = new Foo();

Foo has a close() method. Let's say I know that a lot of the classes will have a close() method but since they were poorly devised and are legacy that I cannot re-write, I would like to find out a generic solution to invoke a method I know they all have, despite them not inheriting from a base class or interface.

I would like to have a method in my FooHandling class that accepts initialized objects and invokes their close() method. The objects will by no means inherit from the same base class, so they're totally different in nature, but all have a method with the same name. So, in FooHandler I'd like to have something like this:

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`.
}

So is there some neat trick I could use on an already instantiated object and still do that?

Is there a way to check if a class has a method

Class#getMethods()

Returns an array containing Method objects reflecting all the public member methods of the class or interface represented by this Class object, including those declared by the class or interface and those inherited from superclasses and superinterfaces

Class#getMethod(String,Class...)

Returns a Method object that reflects the specified public member method of the class or interface represented by this Class object. The name parameter is a String specifying the simple name of the desired method .

Throws:

NoSuchMethodException - if a matching method is not found

Sample code:

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

output:

close method is invoked

Yes you could use reflection for this, something like this would do it

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

The method to get the method object is Class#getMethod(String, Class...) , it allows you to find the specific method you are looking for using it's signature (the formal parameter list) so among all overloaded methods you get exactly the one you need.

In all the exception thrown the one you might be the most interested in is InvocationTargetException which tells you that the method invoked has thrown an exception.

You could do what others have already answered, but there are some ready-made options if you do not want to mess too much with reflection. An example is 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
}
...

These libraries also tend to keep a method cache, so you get fast reflection; by caching you skip the slow part of reflection: method lookup.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM