4

是否可以从java动态调用类的方法?

例如,假设我有一个类的引用,例如字符串:'com.foo.Bar',或com.foo.Bar.class,或任何其他需要的东西..)。我有一个字符串数组/列表,例如[First, Last, Email].

我想简单地遍历这个数组,然后调用'validate' + element我引用的类的方法。例如:

MyInterface item = //instantiate the com.foo.Bar class here somehow, I'm not sure how.

item.validateFirst();
item.validateLast();
item.validateEmail();

我希望上面的代码行动态发生,所以我可以更改对不同类的引用,并且我的字符串列表中的名称可以更改,但它仍然会调用validate + name它引用的任何类的方法。

那可能吗?

4

6 回答 6

7

最简单的方法是使用反射

鉴于...

package com.foo;

public class Bar {

    public void validateFirst() {
        System.out.println("validateFirst");
    }

    public void validateLast() {
        System.out.println("validateLast");
    }

    public void validateEmail() {
        System.out.println("validateEmail");
    }

}

你可以使用类似...

String methodNames[] = new String[]{"First", "Last", "Email"};
String className = "com.foo.Bar";
try {

    Class classRef = Class.forName(className);
    Object instance = classRef.newInstance();

    for (String methodName : methodNames) {

        try {

            Method method = classRef.getDeclaredMethod("validate" + methodName);
            method.invoke(instance);

        } catch (NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException ex) {
            ex.printStackTrace();
        }

    }

} catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
    ex.printStackTrace();
}

查找方法并执行它们。

您将需要决定处理错误的最佳方法以及它们对您的意义,但将想法扩展到可重用方法并不难......

更新了评论中讨论的概念

给定....

public interface Validator {
    public boolean isValid(Properties formProperties);
}

我们可以创建一个或多个...

public class UserRegistrationValidator implements Validator {
    public boolean isValid(Properties formProperties) {
        boolean isValid = false;
        // Required fields...
        if (formProperties.containsKey("firstName") && formProperties.containsKey("lastName") && formProperties.containsKey("email")) {
            // Further processing, valid each required field...
        }
        if (isValid) {
            // Process optional parameters
        }
        return isValid;
    }
}

然后从我们的输入控制器中,我们可以查看并验证所需的表单

public class FormController ... {

    private Map<String, Validator> validators;

    public void validForm(String formName, Properties formProperties) {
        boolean isValid = false;
        Validator validator = validators.get(formName);
        if (validator != null) {
            isValid = validate.isValid(formProperties);
        }
        return isValid;
    }

}

当然你需要提供一些注册方式,Validators根据你使用的主干框架和你可以使用的参数可能会有差异(你不必使用Properties,但它基本上只是一个Map<String, String>......)

于 2013-09-13T05:28:28.163 回答
5

你可以写这样的东西......它将类的名称作为字符串作为参数,方法名称及其参数

private static String invoke(String aClass, String aMethod, Class<?>[] params,
            Object[] args) throws Exception {
        String resp = "";
        Class<?> c = Class.forName(aClass);
        Method m = c.getDeclaredMethod(aMethod, params);
        Object i = c.newInstance();
        resp = m.invoke(i, args).toString();

        return resp;
}

您还可以参考关于反射的 oracle 教程......它演示了如何调用方法 http://docs.oracle.com/javase/tutorial/reflect/member/methodInvocation.html

于 2013-09-13T05:21:34.710 回答
2

可以使用反射

  1. 首先,从 FQN(完全限定名,即包含包的类名)创建一个新类。

  2. 然后你遍历你的elements并调用"validate"你的项目上的方法。

    Class<?> clazz = Class.forName("com.foo.Bar");
    Object item = clazz.newInstance(); 
    for (String element : elements) {
        Method method = clazz.getDeclaredMethod("validate" + element);
        method.invoke(item);
    }
于 2013-09-13T05:21:09.903 回答
1

您可以使用反射,但我最喜欢的方法是使用 beanutils,例如:

Bar b1 = //...
BeanUtils.getProperty(b1, "first");
BeanUtils.getProperty(b1, "last");

请注意,您的类必须符合 javabean 约定。您可以在此博客文章中阅读有关 beanutils的更多信息(免责声明我是博客作者)

于 2013-09-13T05:23:24.670 回答
1

如果事先知道类的名称,使用Class.forName(yourClassname) 那样的话,就可以调用类,然后,就可以调用它的方法了。

于 2013-09-13T05:23:38.627 回答
0

是的,使用反射。在您的对象上使用Class.getDeclaredMethod

Object validator = <your object instance>;
final String[] values = {
  "Item1","Item2","Item3"
}
for(final String s : values) {
  Method m = validator.getDeclaredMethod("validate" + s,String.class);
  try {
    Object result = m.invoke(validator, s);
  }
  catch(ex) {}
}
于 2013-09-13T05:25:03.947 回答