How to generically implement calling methods store

2019-07-24 17:33发布


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

2条回答
甜甜的少女心
2楼-- · 2019-07-24 17:55


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

查看更多
爱情/是我丢掉的垃圾
3楼-- · 2019-07-24 17:59

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!
查看更多
登录 后发表回答