Execute method by name java

How do I invoke a Java method when given the method name as a string?

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.

23 Answers 23

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

Was a little upset by the fact that Java uses type erasure, but knowing that at least it has Reflection cheers me up again 😀 And now with lambdas in Java 8 the language is really getting up to speed with modern development. Only thing missing now is native support to getters and setters, or properties as they’re known in C#.

Not a fair -1. Henrik is probably not advocating squashing exceptions and didn’t write anything for them because he is just trying to demonstrate reflection.

Читайте также:  Питон задача шнурки объяснение

Plus one for showing some potential exceptions. If I had written this, it would be . catch(Exception e)< .

I got «variable may not have been initialized» for the method in method.invoke(obj, arg1, arg2. ); . a method = null; solves the problem but mentioning it in the answer is not a bad idea.

@DeaMon1 Java methods don’t use «exit codes», but if the method returns anything, invoke will return whatever it returned. If an exception occurs running the method, the exception will be wrapped in an InvocationTargetException .

Class c = Class.forName("class name"); Method method = c.getDeclaredMethod("method name", parameterTypes); method.invoke(objectToInvokeOn, params); 
  • «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

Wrong. Yes, getDeclaredMethod does work with private and protected methods. BUT: it does not work with methods defined in superclasses (inherited methods). So, it depends strongly on what you want to do. In many cases you want it to work regardless of the exact class in which the method is defined.

What should I put inside of and method.invoke() if the method I’m calling doesn’t accept any parameters at all? It seems that I still have to provide second parameter, should it be some empty Object array?

For those who want a straight-forward code example in Java 7:

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"; ClassdogClass = 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 = ; 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(); 
Dog dog = new Dog(); Method method = Dog.class.getMethod(methodName, . ); method.invoke(dog, . ); 

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

+1 for the only answer that recognized that the OP specified «no parameters» in his question (and because it was what I was looking for too).

出现异常错误: java.lang.IllegalAccessException (未捕获)»线程=main», java.lang.reflect.AccessibleObject.checkAccess(), 行=596 bci=38

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.

I disagree. It’s very easy to write such code to be secure and I have done so in multiple languages. For example, one could make a set of allowable methods, and only allow a method to be invoked if it’s name is in the set. Even more secure (yet still bone-head simple) would be limiting each allowed method to a specific state, and not allowing the method to be invoked unless the thread/interface/user/whatever fits such criteria.

Never be so categoricall about such issues. Right now I’m creating a simple program to allow the user to define arbitrary tasks over arbitrary objects using web interfaces. I know it is, indeed, insecure, but proper testing is performed once the config is received, and it allows a non-programmer to easilly configure the tasks, and also gives programmes the ability to link custom classes to the generic code (thats the part I use reflection to, in order to allow them to configure which methods to use via web interface) without having to update the GUI.

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. 
* 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[]; 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; >

Источник

How to call a method by name (String) in Java?

Every instance of class A has an instance of class B . A should call different methods in B depending on its member variable method_num . This is an implementation that does what I want:

public class A < private B myB = new B(); public int method_num = 1; public callBMethod() < if ( method_num == 1 ) myB.method1(); else myB.method2(); >> public class B < public method1() < >public method2() < >> 

But instead of doing myA.method_num = 1 , I want to be able to somehow pass B’s method1 or method2 directly. How can I do that?

@Andreas: there’s no such a thing, unfortunately. But in any case, you wouldn’t be passing the name, then.

5 Answers 5

If you don’t want to use reflection (and this is an excellent goal) then there are some neat features of enum s that allow you to set up an enum as a proxy.

public class A < private B myB = new B(); public int method_num = 1; public void callBMethod() < // Could do it by name. BMethods.valueOf("method1").call(myB); // Or by number. BMethods.values()[method_num].call(myB); >> enum BMethods < method1 < @Override public void call(B b) < b.method1(); >>, method2 < @Override public void call(B b) < b.method2(); >>; public abstract void call (B b); > public class B < public void method1() < >public void method2() < >> 

@Woot4Moo — er . for each method in class B you need an enum that proxies it. I accept that this becomes cumbersome as the number of methods in B increases but it avoids reflection which, to me, is a laudable gain.

Sure agree. I would treat it as just another «interface» between two modules. Just wanted to mention the scaling piece for future readers.

In the same vein — using this method it is still possible to trace all users of every method of B and be absolutely sure you have them all. Once you use reflection — anywhere in your code — this is no longer possible.

I think you can use reflection like this:

java.lang.reflect.Method method; try < method = obj.getClass().getMethod(methodName, param1.class, param2.class, ..); >catch (SecurityException e) < // . >catch (NoSuchMethodException e) < // . >try < method.invoke(obj, arg1, arg2. ); >catch (IllegalArgumentException e) < //do proper handling >catch (IllegalAccessException e) catch (InvocationTargetException e) 

You cannot. Java doesn't treat functions as first class objects, because it doesn't have functional features like Python or C#.

You can create a Command interface and pass that object reference:

@duffymo & arshajii -- Every "improvement" to Java since about 1.2 has been done in the worst possible way, further corrupting what was originally a very "clean" design. It's not the added function, it's the way it's apt to be designed and implemented.

Maybe with Runnable objects ? You can pass from B a runnable, and call .run() directly from A

@Woot4Moo: While I agree this is a short (too short?) answer, I thought that using a runnable object is both appropriate and not already in existing answers.

ah yes agree it wasn't in other answers, but it didn't provide a code based solution like the others 🙂

Java reflection API provides you a way, where a Method type of object could be passed along with the target object and then the method could be invoked on the target object.

Method m; // The method to be invoked Object target; // The object to invoke it on Object[] args; // The arguments to pass to the method // An empty array; used for methods with no arguments at all. static final Object[] nullargs = new Object[] <>; /** This constructor creates a Command object for a no-arg method */ public Command(Object target, Method m) < this(target, m, nullargs); >/** * This constructor creates a Command object for a method that takes the * specified array of arguments. Note that the parse() method provides * another way to create a Command object */ public Command(Object target, Method m, Object[] args) < this.target = target; this.m = m; this.args = args; >/** * Invoke the Command by calling the method on its target, and passing the * arguments. See also actionPerformed() which does not throw the checked * exceptions that this method does. */ public void invoke() throws IllegalAccessException, InvocationTargetException < m.invoke(target, args); // Use reflection to invoke the method >

Источник

Call a function by its name, given from string java

I have searched a bit into lambda funcions but they are not supported. I was thinking about going for Reflection, but I am a bit new to programming, so I am not so familiar with the subject. This whole question was brought up on my java OOP class, when I started GUI (Swing, swt) programming, and events. I found that using object.addActionCommand() is very ugly, because I would later need to make a Switch and catch the exact command I wanted. I would rather do something like object.attachFunction(btn1_click) , so that it would call the btn1_click function when the event click was raised.

5 Answers 5

Java has methods, not functions. The difference is that methods have classes; you need to know the class to call the method. If it's an instance method, you need an instance to call it on, but OTOH it does mean that you can look the method up easily:

public void callByName(Object obj, String funcName) throws Exception < // Ignoring any possible result obj.getClass().getDeclaredMethod(funcName).invoke(obj); >

Note that there are a lot of potential exceptions out of this and things get more complex if you want to pass arguments in.

If you are talking about a class method, what you do is slightly different:

public void callClassByName(Class cls, String funcName) throws Exception < // Ignoring any possible result cls.getDeclaredMethod(funcName).invoke(null); >

You might also want to explore using a java.lang.reflect.Proxy .

Источник

Оцените статью