If I have two variables:
Object obj;
String methodName = "getName";
Without knowing the class of obj
, how can I call the method identified by methodName
on it?
The method being called has no parameters, and a String
return value. It's a getter for a Java bean.
Coding from the hip, it would be something like:
java.lang.reflect.Method method;
try {
method = obj.getClass().getMethod(methodName, param1.class, param2.class, ..);
} catch (SecurityException e) { ... }
catch (NoSuchMethodException e) { ... }
The parameters identify the very specific method you need (if there are several overloaded available, if the method has no arguments, only give methodName
).
Then you invoke that method by calling
try {
method.invoke(obj, arg1, arg2,...);
} catch (IllegalArgumentException e) { ... }
catch (IllegalAccessException e) { ... }
catch (InvocationTargetException e) { ... }
Again, leave out the arguments in .invoke
, if you don't have any. But yeah. Read about Java Reflection
Use method invocation from reflection:
Class<?> c = Class.forName("class name");
Method method = c.getDeclaredMethod("method name", parameterTypes);
method.invoke(objectToInvokeOn, params);
Where:
"class name" is the name of the class
objectToInvokeOn is of type Object and is the object you want to invoke the method on
"method name" is the name of the method you want to call
parameterTypes is of type Class[] and declares the parameters the method takes
params is of type Object[] and declares the parameters to be passed to the method
For those who want a straight-forward code example in Java 7:
Dog
class:
package com.mypackage.bean;
public class Dog {
private String name;
private int age;
public Dog() {
// empty constructor
}
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void printDog(String name, int age) {
System.out.println(name + " is " + age + " year(s) old.");
}
}
ReflectionDemo
class:
package com.mypackage.demo;
import java.lang.reflect.*;
public class ReflectionDemo {
public static void main(String[] args) throws Exception {
String dogClassName = "com.mypackage.bean.Dog";
Class<?> dogClass = Class.forName(dogClassName); // convert string classname to class
Object dog = dogClass.newInstance(); // invoke empty constructor
String methodName = "";
// with single parameter, return void
methodName = "setName";
Method setNameMethod = dog.getClass().getMethod(methodName, String.class);
setNameMethod.invoke(dog, "Mishka"); // pass arg
// without parameters, return string
methodName = "getName";
Method getNameMethod = dog.getClass().getMethod(methodName);
String name = (String) getNameMethod.invoke(dog); // explicit cast
// with multiple parameters
methodName = "printDog";
Class<?>[] paramTypes = {String.class, int.class};
Method printDogMethod = dog.getClass().getMethod(methodName, paramTypes);
printDogMethod.invoke(dog, name, 3); // pass args
}
}
Output: Mishka is 3 year(s) old.
You can invoke the constructor with parameters this way:
Constructor<?> dogConstructor = dogClass.getConstructor(String.class, int.class);
Object dog = dogConstructor.newInstance("Hachiko", 10);
Alternatively, you can remove
String dogClassName = "com.mypackage.bean.Dog";
Class<?> dogClass = Class.forName(dogClassName);
Object dog = dogClass.newInstance();
and do
Dog dog = new Dog();
Method method = Dog.class.getMethod(methodName, ...);
method.invoke(dog, ...);
Suggested reading: Creating New Class Instances
Method
object?
The method can be invoked like this. There are also more possibilities (check the reflection api), but this is the simplest one:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.junit.Assert;
import org.junit.Test;
public class ReflectionTest {
private String methodName = "length";
private String valueObject = "Some object";
@Test
public void testGetMethod() throws SecurityException, NoSuchMethodException, IllegalArgumentException,
IllegalAccessException, InvocationTargetException {
Method m = valueObject.getClass().getMethod(methodName, new Class[] {});
Object ret = m.invoke(valueObject, new Object[] {});
Assert.assertEquals(11, ret);
}
}
First, don't. Avoid this sort of code. It tends to be really bad code and insecure too (see section 6 of Secure Coding Guidelines for the Java Programming Language, version 2.0).
If you must do it, prefer java.beans to reflection. Beans wraps reflection allowing relatively safe and conventional access.
To complete my colleague's answers, You might want to pay close attention to:
static or instance calls (in one case, you do not need an instance of the class, in the other, you might need to rely on an existing default constructor that may or may not be there)
public or non-public method call (for the latter,you need to call setAccessible on the method within an doPrivileged block, other findbugs won't be happy)
encapsulating into one more manageable applicative exception if you want to throw back the numerous java system exceptions (hence the CCException in the code below)
Here is an old java1.4 code which takes into account those points:
/**
* Allow for instance call, avoiding certain class circular dependencies. <br />
* Calls even private method if java Security allows it.
* @param aninstance instance on which method is invoked (if null, static call)
* @param classname name of the class containing the method
* (can be null - ignored, actually - if instance if provided, must be provided if static call)
* @param amethodname name of the method to invoke
* @param parameterTypes array of Classes
* @param parameters array of Object
* @return resulting Object
* @throws CCException if any problem
*/
public static Object reflectionCall(final Object aninstance, final String classname, final String amethodname, final Class[] parameterTypes, final Object[] parameters) throws CCException
{
Object res;// = null;
try {
Class aclass;// = null;
if(aninstance == null)
{
aclass = Class.forName(classname);
}
else
{
aclass = aninstance.getClass();
}
//Class[] parameterTypes = new Class[]{String[].class};
final Method amethod = aclass.getDeclaredMethod(amethodname, parameterTypes);
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
amethod.setAccessible(true);
return null; // nothing to return
}
});
res = amethod.invoke(aninstance, parameters);
} catch (final ClassNotFoundException e) {
throw new CCException.Error(PROBLEM_TO_ACCESS+classname+CLASS, e);
} catch (final SecurityException e) {
throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_SECURITY_ISSUE, e);
} catch (final NoSuchMethodException e) {
throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_NOT_FOUND, e);
} catch (final IllegalArgumentException e) {
throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_ILLEGAL_ARGUMENTS+String.valueOf(parameters)+GenericConstants.CLOSING_ROUND_BRACKET, e);
} catch (final IllegalAccessException e) {
throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_ACCESS_RESTRICTION, e);
} catch (final InvocationTargetException e) {
throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_INVOCATION_ISSUE, e);
}
return res;
}
Object obj;
Method method = obj.getClass().getMethod("methodName", null);
method.invoke(obj, null);
//Step1 - Using string funClass to convert to class
String funClass = "package.myclass";
Class c = Class.forName(funClass);
//Step2 - instantiate an object of the class abov
Object o = c.newInstance();
//Prepare array of the arguments that your function accepts, lets say only one string here
Class[] paramTypes = new Class[1];
paramTypes[0]=String.class;
String methodName = "mymethod";
//Instantiate an object of type method that returns you method name
Method m = c.getDeclaredMethod(methodName, paramTypes);
//invoke method with actual params
m.invoke(o, "testparam");
Indexing (faster)
You can use FunctionalInterface
to save methods in a container to index them. You can use array container to invoke them by numbers or hashmap to invoke them by strings. By this trick, you can index your methods to invoke them dynamically faster.
@FunctionalInterface
public interface Method {
double execute(int number);
}
public class ShapeArea {
private final static double PI = 3.14;
private Method[] methods = {
this::square,
this::circle
};
private double square(int number) {
return number * number;
}
private double circle(int number) {
return PI * number * number;
}
public double run(int methodIndex, int number) {
return methods[methodIndex].execute(number);
}
}
Lambda syntax
You can also use lambda syntax:
public class ShapeArea {
private final static double PI = 3.14;
private Method[] methods = {
number -> {
return number * number;
},
number -> {
return PI * number * number;
},
};
public double run(int methodIndex, int number) {
return methods[methodIndex].execute(number);
}
}
O(1)
.
If you do the call several times you can use the new method handles introduced in Java 7. Here we go for your method returning a String:
Object obj = new Point( 100, 200 );
String methodName = "toString";
Class<String> resultType = String.class;
MethodType mt = MethodType.methodType( resultType );
MethodHandle methodHandle = MethodHandles.lookup().findVirtual( obj.getClass(), methodName, mt );
String result = resultType.cast( methodHandle.invoke( obj ) );
System.out.println( result ); // java.awt.Point[x=100,y=200]
invokeExact
whenever you can. For that, the call site signature has to match the method handle type exactly though. It usually takes a little tinkering to get to work. In this case you'd need to cast the first parameter with: methodHandle = methodHandle.asType(methodHandle.type().changeParameterType(0, Object.class));
and then invoke like String result = (String) methodHandle.invokeExact(obj);
try {
YourClass yourClass = new YourClass();
Method method = YourClass.class.getMethod("yourMethodName", ParameterOfThisMethod.class);
method.invoke(yourClass, parameter);
} catch (Exception e) {
e.printStackTrace();
}
This sounds like something that is doable with the Java Reflection package.
http://java.sun.com/developer/technicalArticles/ALT/Reflection/index.html
Particularly under Invoking Methods by Name:
import java.lang.reflect.*;
public class method2 {
public int add(int a, int b)
{
return a + b;
}
public static void main(String args[])
{
try {
Class cls = Class.forName("method2");
Class partypes[] = new Class[2];
partypes[0] = Integer.TYPE;
partypes[1] = Integer.TYPE;
Method meth = cls.getMethod(
"add", partypes);
method2 methobj = new method2();
Object arglist[] = new Object[2];
arglist[0] = new Integer(37);
arglist[1] = new Integer(47);
Object retobj
= meth.invoke(methobj, arglist);
Integer retval = (Integer)retobj;
System.out.println(retval.intValue());
}
catch (Throwable e) {
System.err.println(e);
}
}
}
Here are the READY TO USE METHODS:
To invoke a method, without Arguments:
public static void callMethodByName(Object object, String methodName) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
object.getClass().getDeclaredMethod(methodName).invoke(object);
}
To invoke a method, with Arguments:
public static void callMethodByName(Object object, String methodName, int i, String s) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
object.getClass().getDeclaredMethod(methodName, int.class, String.class).invoke(object, i, s);
}
Use the above methods as below:
package practice;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
public class MethodInvoke {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException {
String methodName1 = "methodA";
String methodName2 = "methodB";
MethodInvoke object = new MethodInvoke();
callMethodByName(object, methodName1);
callMethodByName(object, methodName2, 1, "Test");
}
public static void callMethodByName(Object object, String methodName) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
object.getClass().getDeclaredMethod(methodName).invoke(object);
}
public static void callMethodByName(Object object, String methodName, int i, String s) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
object.getClass().getDeclaredMethod(methodName, int.class, String.class).invoke(object, i, s);
}
void methodA() {
System.out.println("Method A");
}
void methodB(int i, String s) {
System.out.println("Method B: "+"\n\tParam1 - "+i+"\n\tParam 2 - "+s);
}
}
Output:
Method A Method B: Param1 - 1 Param 2 - Test
Method method = someVariable.class.getMethod(SomeClass);
String status = (String) method.invoke(method);
SomeClass
is the class and someVariable
is a variable.
Please refer following code may help you.
public static Method method[];
public static MethodClass obj;
public static String testMethod="A";
public static void main(String args[])
{
obj=new MethodClass();
method=obj.getClass().getMethods();
try
{
for(int i=0;i<method.length;i++)
{
String name=method[i].getName();
if(name==testMethod)
{
method[i].invoke(name,"Test Parameters of A");
}
}
}
catch(Exception ex)
{
System.out.println(ex.getMessage());
}
}
Thanks....
Student.java
class Student{
int rollno;
String name;
void m1(int x,int y){
System.out.println("add is" +(x+y));
}
private void m3(String name){
this.name=name;
System.out.println("danger yappa:"+name);
}
void m4(){
System.out.println("This is m4");
}
}
StudentTest.java
import java.lang.reflect.Method;
public class StudentTest{
public static void main(String[] args){
try{
Class cls=Student.class;
Student s=(Student)cls.newInstance();
String x="kichha";
Method mm3=cls.getDeclaredMethod("m3",String.class);
mm3.setAccessible(true);
mm3.invoke(s,x);
Method mm1=cls.getDeclaredMethod("m1",int.class,int.class);
mm1.invoke(s,10,20);
}
catch(Exception e){
e.printStackTrace();
}
}
}
You should use reflection - init a class object, then a method in this class, and then invoke this method on an object with optional parameters. Remember to wrap the following snippet in try-catch block
Hope it helps!
Class<?> aClass = Class.forName(FULLY_QUALIFIED_CLASS_NAME);
Method method = aClass.getMethod(methodName, YOUR_PARAM_1.class, YOUR_PARAM_2.class);
method.invoke(OBJECT_TO_RUN_METHOD_ON, YOUR_PARAM_1, YOUR_PARAM_2);
using import java.lang.reflect.*;
public static Object launchProcess(String className, String methodName, Class<?>[] argsTypes, Object[] methodArgs)
throws Exception {
Class<?> processClass = Class.forName(className); // convert string classname to class
Object process = processClass.newInstance(); // invoke empty constructor
Method aMethod = process.getClass().getMethod(methodName,argsTypes);
Object res = aMethod.invoke(process, methodArgs); // pass arg
return(res);
}
and here is how you use it:
String className = "com.example.helloworld";
String methodName = "print";
Class<?>[] argsTypes = {String.class, String.class};
Object[] methArgs = { "hello", "world" };
launchProcess(className, methodName, argsTypes, methArgs);
With jooR it's merely:
on(obj).call(methodName /*params*/).get()
Here is a more elaborate example:
public class TestClass {
public int add(int a, int b) { return a + b; }
private int mul(int a, int b) { return a * b; }
static int sub(int a, int b) { return a - b; }
}
import static org.joor.Reflect.*;
public class JoorTest {
public static void main(String[] args) {
int add = on(new TestClass()).call("add", 1, 2).get(); // public
int mul = on(new TestClass()).call("mul", 3, 4).get(); // private
int sub = on(TestClass.class).call("sub", 6, 5).get(); // static
System.out.println(add + ", " + mul + ", " + sub);
}
}
This prints:
3, 12, 1
This is working fine for me :
public class MethodInvokerClass {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, ClassNotFoundException, InvocationTargetException, InstantiationException {
Class c = Class.forName(MethodInvokerClass.class.getName());
Object o = c.newInstance();
Class[] paramTypes = new Class[1];
paramTypes[0]=String.class;
String methodName = "countWord";
Method m = c.getDeclaredMethod(methodName, paramTypes);
m.invoke(o, "testparam");
}
public void countWord(String input){
System.out.println("My input "+input);
}
}
Output:
My input testparam
I am able to invoke the method by passing its name to another method (like main).
For those who are calling the method within the same class from a non-static method, see below codes:
class Person {
public void method1() {
try {
Method m2 = this.getClass().getDeclaredMethod("method2");
m1.invoke(this);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
public void method2() {
// Do something
}
}
Suppose you're invoking a static method from a static method within the same class. To do that, you can sample the following code.
class MainClass
{
public static int foo()
{
return 123;
}
public static void main(String[] args)
{
Method method = MainClass.class.getMethod("foo");
int result = (int) method.invoke(null); // answer evaluates to 123
}
}
To explain, since we're not looking to perform true object-oriented programming here, hence avoiding the creation of unnecessary objects, we will instead leverage the class
property to invoke getMethod()
.
Then we will pass in null
for the invoke()
method because we have no object to perform this operation upon.
And finally, because we, the programmer, know that we are expecting an integer, then we explicitly cast the return value of the invoke()
invocation to an integer.
Now you may wonder: "What even is the point of doing all this non-object oriented programming in Java?"
My use case was to solve Project Euler problems in Java. I have a single Java source file containing all the solutions, and I wanted to pass in command line arguments to determine which Project Euler problem to run.
for me a pretty simple and fool proof way would be to simply make a method caller method like so:
public static object methodCaller(String methodName)
{
if(methodName.equals("getName"))
return className.getName();
}
then when you need to call the method simply put something like this
//calling a toString method is unnessary here, but i use it to have my programs to both rigid and self-explanitory
System.out.println(methodCaller(methodName).toString());
className.getName().toString()
? You're missing the whole point of reflection.
Success story sharing
method
inmethod.invoke(obj, arg1, arg2,...);
. amethod = null;
solves the problem but mentioning it in the answer is not a bad idea.invoke
will return whatever it returned. If an exception occurs running the method, the exception will be wrapped in anInvocationTargetException
.