Marek
Marek

Reputation: 215

Dynamically invoking non-static methods

I have dozens of functions which are alternatives to each other. They take an input and return an output, but in each case the output is slightly different. All of them are embedded in a single wrapper class.

I want to invoke them by passing the method name as a string. I would also like to avoid manually maintaining a huge list of unneeded if statements:

if(methodName.equals("method1")
    return method1(argument);
...
else if(methodName.equals("method176")
    return method176(argument);

So far I've figured out how to call the methods dynamically but only if the methods are static:

try {
    method = MyMainClass.class.getDeclaredMethod(methodName, MyArgumentClass.class);
    ResultClass result = (ResultClass)method.invoke(null, myArgument);
    return result;
}
catch(Exception e)
{
    e.printStackTrace();
    System.exit(1);
    return null;
}

Is it possible to this for non-static methods, and invoke the functions on class instances instead of the static class?

Upvotes: 4

Views: 4985

Answers (5)

Adam
Adam

Reputation: 44969

Yes. Using Java reflection just pass the instance to invoke it on as the first argument to the invoke method.

Read: http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Method.html#invoke

try {
    MyArgumentClass argument = new MyArgumentClass();
    MyMainClass instance = new MyMainClass(argument);
    method = MyMainClass.class.getDeclaredMethod(methodName, MyArgumentClass.class);
    ResultClass result = (ResultClass) method.invoke(instance, myArgument);
    return result;
}
catch(Exception e)
{
    e.printStackTrace();
    System.exit(1);
    return null;
}

As pointed out in the other answers, this is not the best approach to your problem. You should implement the Strategy pattern like so:

interface MyOperation{
   public ResultClass execute(MyArgumentClass argument);
}

public class Method1 implements MyOperation {
    public ResultClass execute(MyArgumentClass argument){
      ....
    }
}

public class Method176 implements MyOperation {
    public ResultClass execute(MyArgumentClass argument){
      ....
    }
}

public class DoIt{
    public ResultClass doIt(MyOperation method, MyArgumentClass argument){
       return method.doIt(argument);
    }
}

Upvotes: 5

kidhuvig
kidhuvig

Reputation: 134

Yes it is possible to do so but you have to use the Java Reflection package java.lang.reflect.* Have a look at the "Invoke methods by name" section in this link http://java.sun.com/developer/technicalArticles/ALT/Reflection/

Upvotes: 1

Spencer Kormos
Spencer Kormos

Reputation: 8451

Get an instance of your Method, which is retrieved from the Class like you're doing, then call Method.invoke() with the instance of the class you wish to call the method on.

You may also use some of the beans available from Spring to accomplish something similar, if you're interested in going that route.

Upvotes: 1

Nathan Hughes
Nathan Hughes

Reputation: 96454

Yes, it's possible. Pass in the object you want to invoke the method on as the first argument to the invoke call. Call getClass on the object to get the class to use.

Upvotes: 1

satoshi
satoshi

Reputation: 4113

When possible, better avoid reflection. Seems like your problem can be solved with better design using the Strategy pattern.

Upvotes: 5

Related Questions