当给定方法名称作为字符串时,如何调用 Java 方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/160970/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I invoke a Java method when given the method name as a string?
提问by brasskazoo
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?
在不知道 的类的情况下obj
,如何调用其上标识的方法methodName
?
The method being called has no parameters, and a String
return value. It's a getter for a Java bean.
被调用的方法没有参数和String
返回值。它是 Java bean 的吸气剂。
采纳答案by Henrik Paul
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
).
参数标识您需要的非常具体的方法(如果有几个重载可用,如果方法没有参数,则只给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
同样,.invoke
如果您没有任何参数,请省略 中的参数。但是是的。阅读Java 反射
回答by Owen
Use method invocationfrom 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 classobjectToInvokeOn
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 callparameterTypes
is of typeClass[]
and declares the parameters the method takesparams
is of typeObject[]
and declares the parameters to be passed to the method
"class name"
是类的名称objectToInvokeOn
是 Object 类型并且是您要调用其上的方法的对象"method name"
是您要调用的方法的名称parameterTypes
是类型Class[]
并声明方法采用的参数params
是类型Object[]
并声明要传递给方法的参数
回答by zxcv
This sounds like something that is doable with the Java Reflection package.
这听起来像是 Java Reflection 包可以做到的事情。
http://java.sun.com/developer/technicalArticles/ALT/Reflection/index.html
http://java.sun.com/developer/technicalArticles/ALT/Reflection/index.html
Particularly under Invoking Methods by Name:
特别是在按名称调用方法下:
import java.lang.reflect.*;
导入 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);
}
}
}
回答by chickeninabiscuit
Object obj;
Method method = obj.getClass().getMethod("methodName", null);
method.invoke(obj, null);
回答by Petr Macek
The method can be invoked like this. There are also more possibilities (check the reflection api), but this is the simplest one:
可以像这样调用该方法。还有更多的可能性(检查反射api),但这是最简单的一种:
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);
}
}
回答by VonC
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 constructorthat 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)
- 静态或实例调用(在一种情况下,您不需要类的实例,在另一种情况下,您可能需要依赖可能存在也可能不存在的现有默认构造函数)
- 公共或非公共方法调用(对于后者,您需要在 doPrivileged 块内的方法上调用 setAccessible,其他findbugs 不会高兴)
- 如果您想返回大量的 Java 系统异常,则封装为一个更易于管理的应用异常(因此是下面代码中的 CCException)
Here is an old java1.4 code which takes into account those points:
这是一个旧的 java1.4 代码,它考虑了这些点:
/**
* 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;
}
回答by Tom Hawtin - tackline
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).
首先,不要。避免这种代码。它往往是非常糟糕的代码并且也不安全(请参阅Java 编程语言安全编码指南 2.0 版的第 6 节)。
If you must do it, prefer java.beans to reflection. Beans wraps reflection allowing relatively safe and conventional access.
如果您必须这样做,请选择 java.beans 而非反射。Beans 包装反射允许相对安全和常规的访问。
回答by SMayne
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());
回答by anujin
//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");
回答by silver
For those who want a straight-forward code example in Java 7:
对于那些想要 Java 7 中的直接代码示例的人:
Dog
class:
Dog
班级:
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:
ReflectionDemo
班级:
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.
输出: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
推荐阅读:创建新的类实例