Подтвердить что ты не робот

Как вызвать метод, хранящийся в 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().

Возможно ли это? Если нет, что является простым способом для этого?

4b9b3361

Ответ 1

С выражениями Java 8+ и Lambda

С lambdas (доступно в 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.


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

Ответ 2

Хотя вы можете хранить методы через отражение, обычный способ сделать это - использовать анонимные объекты, которые обертывают функцию, т.е.

  interface IFooBar {
    void callMe();
  }


 'h', new IFooBar(){ void callMe() { showHelp(); } }
 't', new IFooBar(){ void callMe() { teleport(); } }

 HashTable<IFooBar> myHashTable;
 ...
 myHashTable.get('h').callMe();

Ответ 3

Если вы используете 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();