【问题标题】:How to call a method stored in a HashMap? (Java) [duplicate]如何调用存储在 HashMap 中的方法? (Java)[重复]
【发布时间】:2011-05-27 16:35:11
【问题描述】:

我有一个命令列表(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().

这可能吗?如果没有,有什么简单的方法?

【问题讨论】:

  • 只是想知道,但是使用散列图代替嗡嗡声开关有什么好处?
  • 因为没有人愿意记住命令 87 是“吃”。这和我可以简单地将命令、帮助文本等关联在一起的事实。

标签: java hash methods invoke


【解决方案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 接口,但也可以使用我在Java 7 版本的答案中发明的Command-接口。

此外,() -&gt; { ... } 语法还有其他替代方法。您也可以拥有helpteleport 的成员函数,并分别使用YourClass::helpYourClass::teleport 代替。


Java 7 及以下

您真正想要做的是创建一个接口,例如命名为Command(或重复使用例如Runnable),并让您的映射为Map&lt;Character, Command&gt; 类型。像这样:

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

【讨论】:

  • 不支持一流的功能真是太麻烦了:)
  • 我认为这是线程安全的,但我不确定你是否同意它是线程安全的
  • 我怀疑get 操作是线程安全的。但可以肯定的是,您可能想使用Collections.synchronizedMap
  • @9000,答案已更新! :-)
  • 反射“hack”就像一个魅力,如果有人需要传递参数:“methodMap.put('h', Test.class.getMethod("showHelp", String.class));"和 "methodMap.get(cmd).invoke(null, "myParam");"
【解决方案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 一样使用 lambda 表达式的方法。

如果不是最好的方法是制作一个函数对象:

public interface Action { void performAction(); }

Hashmap<string,Action> cmdList;

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

【讨论】:

  • 其实 lambda 表达式已经推迟到 JDK 8。
  • hashMap 函数映射的主要部分是我们想稍后用参数调用它,任何人都可以提供包含参数的示例,例如int func(string p1, int 2) 当我构建 hashMap 时,我不知道值,当事件发生时,我调用 hashmap.get(event).func("now", -1)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-14
  • 1970-01-01
相关资源
最近更新 更多