Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically invoking non-static methods

Tags:

java

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?

like image 225
Marek Avatar asked Dec 12 '22 05:12

Marek


2 Answers

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);
    }
}
like image 163
Adam Avatar answered Dec 23 '22 19:12

Adam


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

like image 33
satoshi Avatar answered Dec 23 '22 20:12

satoshi