【问题标题】:How to generically implement calling methods stored in a HashMap?如何一般地实现存储在 HashMap 中的调用方法?
【发布时间】:2013-09-28 13:52:22
【问题描述】:


我想将某些字符路由到方法,以便在命令行中键入字符时执行该方法。

基于答案How to call a method stored in a HashMap,我使用“命令”设计模式将这些字符映射到方法。

但是我想一般地实现这一点,所以似乎我需要实现反射才能使用 Method 类作为参数。我的尝试是在我的匿名课堂上获得NullPointerException 字段private Method method ......


这是我的代码:
import java.lang.reflect.Method;

public interface InvokesMethod {

    public void invokeMethod() throws Exception;
    public void setMethod(Method method);
} // end of interface


import java.util.HashMap;
import java.lang.reflect.Method;

public class Terminal {

    public HashMap<Character, InvokesMethod> commands;

    public Terminal() {
        this.commands = new HashMap<Character, InvokesMethod>();

        try {
            this.setCommand('p',
                 this.getClass().getDeclaredMethod("printHelloWorld"));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void printHelloWorld() {
        System.out.println("Hello World!");
    }

    private void setCommand(char letter, Method method) {
        this.commands.put(letter, new InvokesMethod() {

            // NullPointerException starts here in the stack-trace:
            private Method method;

            @Override
            public void invokeMethod() throws Exception {
                method.invoke(null);
            }

            @Override
            public void setMethod(Method method) {
                this.method = method;
            }
        }).setMethod(method);
    }

    public void executeCommand(char letter) throws Exception {
        this.commands.get(letter).invokeMethod();
    }
} // end of class


public class Main() {

    public static void main(String[] args) {
        Terminal commandLine = new Terminal();

        try {
            commandLine.executeCommand('p');

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
} // end of class

【问题讨论】:

    标签: java design-patterns reflection hashmap anonymous-class


    【解决方案1】:

    关于您没有启动method 的代码。请记住,executenull 必须调用公共静态方法:

    您的另一个问题,您没有正确启动界面。这是工作示例:

    InvokesMethodItf

    public interface InvokesMethodItf {
    
    public void invokeMethod() throws Exception;
    public void setMethod(Method method);
    } 
    

    InvokesMethod

    public class InvokesMethod implements InvokesMethodItf{
    
    private Method method;
    
    @Override
    public void invokeMethod() throws Exception {
         method.invoke(null);
    }
    
    @Override
    public void setMethod(Method method) {
        this.method = method;
    }
    
    }
    

    终端

    public class Terminal {
    
    public HashMap<Character, InvokesMethodItf> commands;
    
    public Terminal() {
        this.commands = new HashMap<Character, InvokesMethodItf>();
    
        try {
            this.setCommand('p',
                 this.getClass().getDeclaredMethod("printHelloWorld"));
    
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void printHelloWorld() {// method.invoke(null) looking for "static" method
        System.out.println("Hello World!");
    }
    
    
    private void setCommand(char letter, Method method) {
    
        InvokesMethodItf inv = new InvokesMethod();
    
        inv.setMethod(method);
    
        this.commands.put(letter, inv);
    }
    
    public void executeCommand(char letter) throws Exception {
        this.commands.get(letter).invokeMethod();
     }
    }
    

    主要

    public class Main {
    public static void main(String[] args) {
        Terminal commandLine = new Terminal();
    
        try {
            commandLine.executeCommand('p');
    
        } catch (Exception e) {
            e.printStackTrace();
        }
      }
    }
    

    输出:

    Hello World!
    

    【讨论】:

    • 好的,太棒了,感谢@Maxim 的帮助!我用你之前的建议解决了这个问题,在 HashMap 中将方法作为字符串传递,这也简化了代码。我也在这里发布这个可能的解决方案作为答案,干杯:)
    • 我修正了你的答案,它似乎有效,看看上面发布的。我认为它更清楚
    【解决方案2】:


    感谢@Maxim 在这里的原始建议,我有一个替代解决方案,方法是将方法设置为 HashMap 中的字符串 --

    import java.util.HashMap;
    import java.lang.reflect.Method;
    
    public class Terminal {
    
        private HashMap<Character, String> commands;
    
        public Terminal() {
            this.commands = new HashMap<Character, String>();
            this.commands.put('p', "printHelloWorld");
        }
    
        private void printHelloWorld() {
            System.out.println("Hello World!");
        }
    
        public void executeCommand(char letter) throws Exception {
            Method method = getClass().getDeclaredMethod(this.commands.get(letter));
            method.invoke(this);
        }
    


    public class Main {
        public static void main(String[] args) {
            Terminal commandLine = new Terminal();
    
            try {
                commandLine.executeCommand('p');
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    } // end of class
    


    输出:

    Hello World!
    


    现在要弄清楚如何将参数传递给反射方法......

    【讨论】:

    • 好的,所以要使用反射来调用带参数的方法,您必须将每个参数的类作为参数传递给第一个参数之后的.getDeclaredMethod(这是方法的名称作为字符串) .例如,字符串参数将作为String.class 传递。然后在我的.executeCommand 方法中有一个String 参数将允许您将它作为参数传递给.invoke,在第一个参数(这是该方法所作用的对象)之后。
    • 另外,.executeCommand 方法可能需要重载,或者它可以使用“varargs”代替(其中类类型将是 String[].class,因为 String... varargs 确实只是一个字符串数组)。
    猜你喜欢
    • 2011-05-27
    • 1970-01-01
    • 2014-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-10
    • 1970-01-01
    • 2015-08-14
    相关资源
    最近更新 更多