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; >
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 .
How to call Java function of an object when function name is stored in a string variable?
So i need to dynamically call these method FROM the object animalObj.
what i required is the implementation of this
String abc="123"; for(int i=0; i
I know the about code is rubbish, but i need to know how to implement this.
But here all the questions are not dealing with populated object.
3 Answers 3
try < animalObj.getClass().getMethod("getAnimal"+abc.charAt(i)).invoke(animalObj); >catch (SecurityException e) < // . >catch (NoSuchMethodException e) < // . >
thanks this is working.. 🙂 I think, in your example there is no need to assign it to method object right? since u are already invoking it.
String methodName = "getAnimal" + abc.length(); try < animalObj.getClass().getMethod(methodName).invoke(animalObj); >catch (SecurityException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ex)
The multicatch is Java 7 syntax, if you don't use Java 7, you can catch the individual exceptions or just Exception .
You can use reflection but it will make your rubbish code even more rubbish. The right way to do it is to refactor each of the getAnimal? methods into their own class which extends one common class. E.g.
interface GetAnimalWrapper
GetAnimalWrapper animal1 = new GetAnimalWrapper() < void getAnimal()< /* something */ >>;
GetAnimalWrapper animal2 = new GetAnimalWrapper() < void getAnimal()< /* something else */ >>;
Now you can have an array of GetAnimalWrapper objects:
Linked
Related
Hot Network Questions
Subscribe to RSS
To subscribe to this RSS feed, copy and paste this URL into your RSS reader.
Site design / logo © 2023 Stack Exchange Inc; user contributions licensed under CC BY-SA . rev 2023.7.27.43548
By clicking “Accept all cookies”, you agree Stack Exchange can store cookies on your device and disclose information in accordance with our Cookie Policy.