java - 我怎么调用Java方法,如果给定方法名作为一个字符串?

  显示原文与译文双语对照的内容

如果有两个变量:


Object obj;
String methodName ="getName";

不知道 obj的类别,如何调用由 methodName 标识的方法?

调用的方法没有参数,以及 String 返回值。 于一个 javabean, 它是一个getter.相关

时间:

从臀部编码,就像:


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) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {

如果你没有任何参数,请再次忽略。invoke中的参数。 但是是的。阅读关于 Java反射

使用反射:

http://java.sun.com/docs/books/tutorial/reflect/member/methodInvocation.html


Class<?> c = Class.forName("class name");
Method method = c.getDeclaredMethod ("method name", parameterTypes)
method.invoke (objectToInvokeOn, params)

在哪里:

"类名"是类的名称

objectToInvokeOn是类型对象,它是你想要调用的对象的对象是你要调用的方法的名称

parameterTypes的类型为 [],decalres的参数为

params是对象 []的类型,声明传递给方法的参数

这里方法可以像这样调用。 还有更多的可能性( 检查反射 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);
 }



}

首先,不要这样。避免这种代码。 它往往是非常糟糕的代码和不安全的( 于偶尔的暂停,版本相关 2.0, 安全编码指南请参见部分 6.) 。

如果你必须这样做,请将 java.beans 更改为反射。 bean封装反射,允许相对安全和常规的访问。

要完成我的同事的回答,你可能需要密切关注:

  • 静态调用或者实例调用( 在一个案例中,你不需要类的实例,请在其他,你可能需要依靠一个现有默认构造函数,可能或者可能不存在)
  • 公共或非公共方法调用( 对于后者,你需要调用该方法到 doPrivileged 块内,其他上 setAccessible findbugs将会很不愉快 )
  • 在下面的代码中),封装到一个更易于管理的实用性强的异常如果你希望引发众多的java系统异常( 因此随着时光倒流 CCException

下面是一个考虑到这些点的旧 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;
}


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


Object obj;

Method method = obj.getClass().getMethod("methodName", null);

method.invoke(obj, null);

这听起来与Java反射包类似。

http://java.sun.com/developer/technicalArticles/ALT/Reflection/index.html

特别在按名称调用方法时:

导入 java.lang. 反射。* ;


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

你可以使用一个 Eclipse 插件来生成私有方法调用。 因此,每次需要调用私有方法( 单元测试中常见的场景) 时都不需要代码和实参。

http://code.google.com hexacta-booster/

对于我来说,一个非常简单和愚蠢的方法就是简单地创建一个方法调用方法,如下所示:


public static object methodCaller(String methodName)
{
 if(methodName.equals("getName"))
 return className.getName();
}

然后,当你需要调用这个方法时,只需输入如下内容


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

...