Как вызвать метод, хранящийся в HashMap? (Джава)
У меня есть список команд (i, h, t и т. Д.), Которые пользователь будет вводить в командной строке / терминале Java-программы. Я хотел бы сохранить хэш пар команд / методов:
'h', showHelp()
't', teleport()
Так что я могу иметь код что-то вроде:
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().
Это возможно? Если нет, то каков легкий путь к этому?
3 ответа
С Java 8+ и лямбда-выражениями
С лямбдами (доступны в Java 8+) мы можем сделать это следующим образом:
class Test {
public static void main(String[] args) throws Exception {
Map<Character, Runnable> 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"
}
}
В этом случае я был ленив и повторно использовал Runnable
интерфейс, но можно также использовать Command
-интерфейс, который я придумал в Java 7 версии ответа.
Кроме того, есть альтернативы () -> { ... }
синтаксис. Вы также можете иметь функции-члены для help
а также teleport
и использовать YourClass::help
соответственно YourClass::teleport
вместо.
Отличный лямбда-шпаргалка на Programming.Guide.
Обучающее руководство по Oracle здесь: Java Tutorials ™ - лямбда-выражения.
Java 7 и ниже
Что вы действительно хотите сделать, это создать интерфейс, названный, например, Command
(или повторно использовать, например Runnable
), и пусть ваша карта будет типа Map<Character, Command>
, Как это:
import java.util.*;
interface Command {
void runCommand();
}
public class Test {
public static void main(String[] args) throws Exception {
Map<Character, Command> methodMap = new HashMap<Character, Command>();
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"
}
}
Отражение "взломать"
С учетом сказанного, вы можете сделать то, что вы просите (используя рефлексию и Method
учебный класс.)
import java.lang.reflect.*;
import java.util.*;
public class Test {
public static void main(String[] args) throws Exception {
Map<Character, Method> methodMap = new HashMap<Character, Method>();
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");
}
}
Хотя вы можете хранить методы посредством отражения, обычный способ сделать это - использовать анонимные объекты, которые обертывают функцию, т.е.
interface IFooBar {
void callMe();
}
'h', new IFooBar(){ void callMe() { showHelp(); } }
't', new IFooBar(){ void callMe() { teleport(); } }
HashTable<IFooBar> myHashTable;
...
myHashTable.get('h').callMe();
Если вы используете JDK 7, теперь вы можете использовать методы по лямбда-выражению, как.net.
Если не лучший способ сделать объект функции:
public interface Action { void performAction(); }
Hashmap<string,Action> cmdList;
if(!cmdList.containsKey('h'))
System.out.print("No such command.") else cmdList.getValue('h').performAction();