如何在Java中动态调用方法

时间:2014-08-15 04:10:17

标签: java

我对Java很陌生,所以请彻底。我正在创建一个程序,该程序使用方法库来搜索具有各种正则表达式的文本文件。检查列表可能会根据文本文件的类型(文本文件是网络设备配置文件)而更改。某些检查适用于某些设备,不适用于其他设备。每次检查都是通过调用其方法来执行的。我遇到的问题是因为所有检查都不适用,我不知道哪些检查在运行时才适用。因此,当用户选择要检查的设备时,我需要能够使用运行时创建的列表中的String调用方法。 例如: 我想我需要能够使用String调用方法 我的列表中确定执行哪些检查的内容

String[] checklist = {"check100", "check101", "check105"}; // list of checks to perform  
String chk = checklist[0]; // String containing a check to be performed (Function Call)
chk(config); // Where it all goes wrong...  I want to make a call to the check100 method using the value of chk  
...  

public void check100 (String[] configFile){ // performs the configFile check100   
...  
...  
}  

public void check101 (String[] configFile){ // performs the configFile check101     
...  
...  
}  
public void check103 (String[] configFile){ //  check not applicable to this device   
...  
...  
}  `

我试过看反射,但似乎无法弄明白。如果有更好的方法在不使用反射的情况下执行此操作,请告诉我。

5 个答案:

答案 0 :(得分:4)

解决方案1:

这可以使用Java的Reflection API

来完成
public static void checkAll( String[] checks, String[] configFile ) {
    Class< ? > cl = Check.class; // Class object where all check methods are.
    for( String check : checks ) {
        Method m = cl.getMethod( check );
        m.invoke( null, configFile );
    }
}

在考虑这种方法之前,您应该阅读几条警告。我没有添加任何错误处理,这段代码将无法编译。 Reflection API可以抛出很多我没有涉及的潜在异常。您应该阅读每种使用的方法,并考虑如何处理每个潜在的错误。

另一个警告是反射很慢,它比静态直接调用每个方法慢得多。如果您担心性能或类型安全性,请考虑使用解决方案2。

解决方案2:

更好的解决方案是为每个检查使用通用接口,例如。

public interface Check {
    void check( String[] configFile );
}

然后创建一组实现该接口的类,并将它们添加到Map中,您可以使用名称或ID来查找要运行的每个检查。这比基于反射的方法快得多,并且是类型安全的。

示例:

public class Check1 implements Check {

    public void check( String[] configFile ) {
        // Do check stuff
    }
}

public class Check2 implements Check {

    public void check( String[] configFile ) {
        // More check stuff
    }
}

public class ConfigCheck {
    public static Map< String, Check > nameToCheck = new HashMap< String, Check >();

    public static void invokeChecks( String[] checks, String[] configFile ) {
        for( String check : checks ) {
            nameToCheck.get( check ).check( configFile );
        }
    }
}

解决方案3:

解决方案3与解决方案2类似,但不是抽象每个检查,而是抽象出您计划检查的每种类型的配置。然后,每种类型都负责调用文件上所有必需的检查。

public interface ConfigType {

    void check( String[] configFile );

}

public class TxtConfig implements ConfigType {

    public void check( String[] configFile ) {
        // Place calls to all required checks.
        // check100( configFile );
        // check101( configFile );
    }
}

public class XMLConfig implements ConfigType {

    public void check( String[] configFile ) {
        // Place calls to all required checks for XML configs
        // check101( configFile );
        // check102( configFile );
    }
}

IMO这是一个非常干净的解决方案,可以扩展接口,其中每个ConfigType子类可用于确定它可以检查哪些配置文件。它还允许其他两个解决方案不提供更好的灵活性。就像只做某些检查,如果之前的“失败”。它还减少了解决方案2中所需的子类数量。您仍然可以在不同的配置类型之间共享检查方法,而无需额外的工作。

答案 1 :(得分:0)

一种解决方案是创建一个界面:

public interface Checkable {
    void check(String[] configFile);
}

然后创建几个实现此接口的类。不幸的是,如果你真的需要超过100种不同的检查,这种方法就不能很好地扩展。

答案 2 :(得分:0)

您可以使用Reflection

这些方面的东西:

String chk = checklist[0];
Method checkMethod = Class.getDeclaredMethod(chk);
checkMethod.invoke();

答案 3 :(得分:0)

您可以像这样使用反射

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

class ReflectionExample {
    public static void main(String[] args){
        String[] checklist = { "check100", "check101", "check105" }; 

        ReflectionExample example = new ReflectionExample();

        for (String methodName : checklist) {
            try {
                Method method = ReflectionExample.class.getMethod(methodName, String[].class);
                String[] configFile = new String[1]; 
                method.invoke(example,configFile);
            }catch(Exception e) {
                e.printStackTrace();
            }
        }
    }

    // ...

    public void check100(String[] configFile) { // performs the configFile
                                                // check100
        System.out.println("check100");
    }

    public void check101(String[] configFile) { // performs the configFile
                                                // check101
        System.out.println("check101");
    }

    public void check103(String[] configFile) { // check not applicable to this
                                                // device
        System.out.println("check103");
    }
}

当然,check105会抛出异常

答案 4 :(得分:0)

警告:不是最佳方法。

执行此操作的一个简单方法是使用 foreach 循环和开关语句:

for (String check: checklist) {
   switch (check) {
        case "check100":  check100();
                 break;
        case "check101":  check101();
                 break;
        default: defaultCheck();
                 break;
    }
}