¿Cómo llamar a un método almacenado en un HashMap? (Java)

Tengo una lista de comandos (i, h, t, etc.) que el usuario ingresará en un progtwig Java de línea de comando / terminal. Me gustaría almacenar un hash de pares de comando / método:

'h', showHelp() 't', teleport() 

Para que pueda tener un código como:

 HashMap cmdList = new HashMap(); cmdList.put('h', showHelp()); if(!cmdList.containsKey('h')) System.out.print("No such command.") else cmdList.getValue('h') // This should run showHelp(). 

es posible? Si no, ¿cuál es una manera fácil de esto?

Con expresiones Java 8+ y Lambda

Con lambdas (disponible en Java 8+) podemos hacerlo de la siguiente manera:

 class Test { public static void main(String[] args) throws Exception { Map commands = new HashMap<>(); // Populate commands map commands.put('h', () -> System.out.println("Help")); commands.put('t', () -> System.out.println("Teleport")); // Invoke some command char cmd = 't'; commands.get(cmd).run(); // Prints "Teleport" } } 

En este caso, yo era flojo y reutilizaba la interfaz de Runnable , pero también podía usar la interfaz de Command que inventé en la versión de Java 7 de la respuesta.

Además, hay alternativas a la syntax () -> { ... } . También podría tener funciones miembro para help y teleport y utilizar YourClass::help resp. YourClass::teleport lugar.

  • Una gran hoja de trucos de Lambda en Programming.Guide.

  • Tutorial de Oracle aquí: The Java Tutorials ™ – Lambda Expressions .


Java 7 y abajo

Lo que realmente quiere hacer es crear una interfaz, nombrada por ejemplo Command (o reutilizar por ejemplo Runnable ), y permita que su mapa sea del tipo Map . Me gusta esto:

 import java.util.*; interface Command { void runCommand(); } public class Test { public static void main(String[] args) throws Exception { Map methodMap = new HashMap(); methodMap.put('h', new Command() { public void runCommand() { System.out.println("help"); }; }); methodMap.put('t', new Command() { public void runCommand() { System.out.println("teleport"); }; }); char cmd = 'h'; methodMap.get(cmd).runCommand(); // prints "Help" cmd = 't'; methodMap.get(cmd).runCommand(); // prints "teleport" } } 

Reflexión “hackear”

Dicho esto, en realidad puedes hacer lo que estás pidiendo (usando la reflexión y la clase Method ).

 import java.lang.reflect.*; import java.util.*; public class Test { public static void main(String[] args) throws Exception { Map methodMap = new HashMap(); methodMap.put('h', Test.class.getMethod("showHelp")); methodMap.put('t', Test.class.getMethod("teleport")); char cmd = 'h'; methodMap.get(cmd).invoke(null); // prints "Help" cmd = 't'; methodMap.get(cmd).invoke(null); // prints "teleport" } public static void showHelp() { System.out.println("Help"); } public static void teleport() { System.out.println("teleport"); } } 

Aunque puede almacenar métodos mediante la reflexión, la forma habitual de hacerlo es utilizar objetos anónimos que envuelven la función, es decir,

  interface IFooBar { void callMe(); } 'h', new IFooBar(){ void callMe() { showHelp(); } } 't', new IFooBar(){ void callMe() { teleport(); } } HashTable myHashTable; ... myHashTable.get('h').callMe(); 

Si está utilizando JDK 7 ahora puede usar métodos por expresión lambda como .net.

Si no, la mejor manera es crear un objeto de función:

 public interface Action { void performAction(); } Hashmap cmdList; if(!cmdList.containsKey('h')) System.out.print("No such command.") else cmdList.getValue('h').performAction();