是否可以从java动态调用类的方法?
例如,假设我有一个类的引用,例如字符串:'com.foo.Bar',或com.foo.Bar.class
,或者其他任何需要的东西......)。我有一个数组/字符串列表,例如[First, Last, Email]
。
我想简单地遍历这个数组,并在我引用的类上调用方法'validate' + element
。 E.g:
MyInterface item = //instantiate the com.foo.Bar class here somehow, I'm not sure how.
item.validateFirst();
item.validateLast();
item.validateEmail();
我希望上面的代码行动态发生,因此我可以将引用更改为其他类,并且我的字符串列表中的名称可以更改,但它仍会在任何类上调用validate + name
方法它有参考。
这可能吗?
答案 0 :(得分:4)
您可以编写类似这样的内容...它将类的名称作为字符串作为参数,方法名称及其参数
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
答案 1 :(得分:2)
最简单的方法是使用reflection
...鉴于
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
,并且根据您使用的骨干框架和您可以使用的参数(您不必使用{{},可能存在差异。 1}},但它基本上只是Properties
...)
答案 2 :(得分:1)
可以使用reflection。
首先,您从FQN创建一个新类(完全限定名称,包括包的类名)。
然后,您遍历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);
}
答案 3 :(得分:1)
你可以使用反射,但我最喜欢的方法是使用beanutils,例如:
Bar b1 = //...
BeanUtils.getProperty(b1, "first");
BeanUtils.getProperty(b1, "last");
请注意,您的类必须符合javabean约定。您可以阅读有关beanutils on this blog post的更多信息(免责声明我是博客作者)
答案 4 :(得分:1)
如果您事先知道班级的名称,请使用Class.forName(yourClassname)
这样,您可以调用该类,然后,您可以调用其方法。
答案 5 :(得分: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) {}
}