繁体   English   中英

如何动态调用Java中的方法

[英]How can I dynamically call methods in Java

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

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   
...  
...  
}  `

我试着看反射,但似乎无法弄清楚。 如果有更好的方法可以不使用反射功能,请告诉我。

解决方案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 );
    }
}

在考虑使用此方法之前,应阅读一些警告。 我没有添加任何错误处理,并且此代码无法编译。 反射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中所需的子类数量。您仍然可以在不同的配置类型之间共享检查方法,而无需进行额外的工作。

一种解决方案是创建一个接口:

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

然后创建几个实现此接口的类。 不幸的是,如果您确实需要100多种不同的支票,这将无法很好地扩展。

您可以使用Reflection

遵循以下原则:

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

您可以这样使用反射

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抛出异常

警告 :不是最好的方法。

一种简单的方法是使用foreach循环和switch语句:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM