How to generically implement calling methods stored in a HashMap?

我的未来我决定 提交于 2019-12-24 05:17:09

问题



I want to route certain chars to methods, so that when the char is typed in the command-line the method is then executed.

Based on the answer How to call a method stored in a HashMap, I'm mapping these chars to methods by using the "Command" design-pattern.

However I want to generically implement this, so it seems that I need to implement reflection in order to use the Method class as a parameter. My attempt is getting a NullPointerException on the field private Method method in my anonymous class...


Here is my code:
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

回答1:


Regards to your code you didn't initiate method. Bear in mind that execute with null you must call public static method:

Your other issue , you didn't initiated interface properly. Here is working example:

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;
}

}

Terminal

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();
 }
}

Main

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

    try {
        commandLine.executeCommand('p');

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

Output:

Hello World!



回答2:



Thanks to @Maxim's original suggestion here, I have an alternate solution by setting the methods as Strings in the HashMap instead --

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


Output:

Hello World!


Now to figure out how to pass parameters to the reflected methods...


来源:https://stackoverflow.com/questions/19063522/how-to-generically-implement-calling-methods-stored-in-a-hashmap

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!