Java反射API及调用带有可变参数的方法

4
我有一个问题需要解决,当我使用Java反射API调用一个接受可变数量参数的方法时,每次都会出现"NoSuchMethodException"的错误。
我要调用的方法声明如下:
public void AddShow(String movieName, String cinemaName, String... days) {
}

以下是执行调用的方法代码:

public void Exec(String command){
    try {
        String[] words = command.split(" ");
        String commandName = words[0];
        Class<? extends UserInterface> thisClass = (Class<? extends UserInterface>)getClass();
        Class<String>[] par = new Class[words.length-1];
        String[] params = new String[words.length-1];
        for(int i = 1; i< words.length; i++){
            params[i-1] = words[i];
            try {
                par[i-1] = (Class<String>) Class.forName("java.lang.String");
            } catch (ClassNotFoundException e) {
                System.out.println("If this shows up, something is siriously wrong... Waht have you done?!");
            }
        }
        Method method;
        if(par.length != 0) {
            method = thisClass.getMethod(commandName, par);
            method.invoke(new UserInterface(CinemaDb), (Object[])params);
        } else {
            method = thisClass.getMethod(commandName);
            method.invoke(new UserInterface(CinemaDb));
        }
    } catch (SecurityException e) {
        System.out.println("Security error, sry again.");
    } catch (NoSuchMethodException e) {
        System.out.println("Wrong command, try again (check the parameters)!");
    } catch (IllegalAccessException e) {
        System.out.println("You don't have access rights, try again.");
    } catch (IllegalArgumentException e) {
        System.out.println("Wrong arguments, try again.");
    } catch (InvocationTargetException e) {
        System.out.println("Invocation error, try again.");
    }
}

如果您知道如何更改我的Exec方法以解决这个问题,我将非常感激。

谢谢!


1
您的Exec方法应该命名为exec,而不是执行Clas.forName("java.lang.string"),可以直接使用String.class:更短,更安全。 - JB Nizet
为什么应该将它命名为“exec”?是因为命名惯例还是您指的其他内容?感谢您的提示,它使我的代码更清晰。 - domderen
是的,为了遵守Java命名规范。在Java中,方法名称始终以小写字母开头。 - JB Nizet
3个回答

4
在Java中,可变参数是通过数组实现的,因此参数为String.class, String.class, 和 String[].class

嗯,还有其他方法吗?因为我无法确定传入的字符串参数是数组的一部分还是普通参数... - domderen

3

存储参数的Object[]应该有两个String参数和一个String[],你正在传递一个扁平的String[]


是的,但我正在使用相同的Exec方法来运行另外几个方法,所以我无法找出传入的参数是数组的一部分还是普通参数。 - domderen
@Tromax 不过,这就是问题所在。你需要想办法弄清楚反射调用所需的内容。 - Dave Newton

3
变长参数部分在编译后表示为String[],因此请使用String[].class
在您的情况下,可能会比较困难,因为您无法确切知道可变长度参数之前有多少参数。因此,如果您调用showFoo str1 str2 str3 str4,您将不知道可变长度参数之前有多少个字符串参数。
因此,您可以在命令字符串中放置一个定界符,告诉解析器在何处添加String[].class,或者只需调用getMethods()并仅按名称获取所需方法(迭代并比较名称)。但是您将无法使用重载。
话虽如此,我认为为反射执行使用这种特殊格式的字符串不是一个好主意(除非它来自外部系统,但那可能是安全问题)。

是的,但我正在使用相同的Exec方法来运行另外几个方法,所以我无法找出传入的参数是数组的一部分还是普通参数。 - domderen
好的,你做不到因为那就是这种情况。看看我的更新第三段中提供的替代方案,但通常情况下,那就是它的本质。 - Bozho
你说得没错,但我正在创建一个用户界面,接受用户传递的命令。因此,我认为使用反射API比创建一个大开关来使用每个命令更容易和简单。 - domderen
用户输入命令时,是以包含方法名称的字符串形式输入的吗?例如,他不能按按钮吗? - Bozho
这是一个命令行工具,所以不算太简单。我尽量保持它的简洁性,但我认为在命令中添加额外的字符作为分隔符是无法避免的。 - domderen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接