代码之家  ›  专栏  ›  技术社区  ›  ryeguy

Java中的函数指针/委托?

  •  12
  • ryeguy  · 技术社区  · 16 年前

    对于我的Java游戏服务器,我发送包的动作ID,它基本上告诉服务器什么是数据包。我想将每个操作ID(整数)映射到一个函数。有没有一种不用开关就能做到这一点的方法?

    9 回复  |  直到 6 年前
        1
  •  21
  •   Johannes Schaub - litb    16 年前

    这个怎么样?

    HashMap<Integer, Runnable> map = new HashMap<Integer, Runnable>();
    map.put(Register.ID, new Runnable() { 
        public void run() { functionA(); }
    });
    map.put(NotifyMessage.ID, new Runnable() { 
        public void run() { functionB(); }
    });
    // ...
    map.get(id).run();
    

    (如果需要传递一些参数,请使用具有适当参数的函数定义自己的接口,并使用该接口而不是可运行的接口)。

        2
  •  2
  •   Bill the Lizard    16 年前

    Java没有真正的函数指针(我们有匿名的内部类来代替)。不过,使用开关并没有什么错,只要你打开的是值而不是类型。你不想使用开关有什么原因吗?似乎您必须在代码中的某个地方对动作ID和动作进行映射,那么为什么不保持简单呢?

        3
  •  1
  •   Adam Rosenfield    16 年前

    Java没有一流的函数指针。为了实现类似的功能,您必须定义和实现一个接口。你可以让匿名内部类更容易使用,但它仍然不是很漂亮。下面是一个例子:

    public interface PacketProcessor
    {
        public void processPacket(Packet packet);
    }
    
    ...
    
    PacketProcessor doThing1 = new PacketProcessor()
    {
        public void processPacket(Packet packet)
        {
            // do thing 1
        }
    };
    // etc.
    
    // Now doThing1, doThing2 can be used like function pointers for a function taking a
    // Packet and returning void
    
        4
  •  1
  •   Josh Lee ZZ Coder    16 年前

    你用过秋千/锥子吗?他们的事件层次结构解决了类似的问题。Java传递函数的方式是用接口,例如

    public interface ActionHandler {
        public void actionPerformed(ActionArgs e);
    }
    

    然后,如果要将整数映射到这些对象上,可以使用类似 java.util.HashMap<Integer,ActionHandler> 去管理它。实际的实现可以进入匿名类(Java的最佳近似“lambda”)或在适当的类中。以下是匿名类方法:

    HashMap<Integer,ActionHandler> handlers;
    handlers.put(ACTION_FROB, new ActionHandler() {
        public void actionPerformed(ActionArgs e) {
            // Do stuff
            // Note that any outer variables you intend to close over must be final.
        }
    });
    handlers.get(ACTION_FROB).actionPerformed(foo);
    

    (编辑)如果您想更加滥用,可以像这样初始化散列映射:

    HashMap<Integer,String> m = new HashMap<Integer,String>() {{
        put(0,"hello");
        put(1,"world");
    }};
    
        5
  •  1
  •   robert    14 年前

    是的,但是使用一个接口意味着你必须为每个回调创建一个接口,这意味着你想要传递它集的每个函数。创建一个委托类来处理这个问题会给你(不是一个真正的函数指针)但是要传递的函数,如果你滥用一个泛型作为返回类型,你就不必强制转换,这会将瓶颈降低到几乎没有。

    C委托(multicastdelegate是正确的)从使用方法method method info获取信息,这与使用java.lang.reflect.method对委托类执行的操作相同。我将delegate(t)类的代码发布到这个站点处理这个extact问题的另一个表单上。我之所以这样做是因为(是)来自C++的,我需要一个更好的方法来传递函数(尤其是虚空),然后必须为函数或更多的函数创建接口。现在我可以选择函数来填充它的参数信息。 哇!很好,可以使用,没有明显的速度损失从JIT或JVM。如果我只学习Java编程一周,任何Java程序员都能做到。

    此外,在创建要传入侦听器的基本侦听器和基本接口时,它也非常有用。不再需要编写另一个侦听器,因为函数名已更改。创建一个代理类有很大的优势,因为它非常有用并且可以通过。

        6
  •  0
  •   Thedric Walker    16 年前

    您可以通过使用责任链模式来实现这一点。

    它是一种将不同对象链接到一起的模式,类似于链接列表。也就是说,每个对象都有一个对链中下一个对象的引用。链中的对象通常处理一个特定的行为。对象之间的流与switch case语句非常相似。

    有一些问题,例如,它分散了您的逻辑,过长的链可能导致性能问题。但是随着这些Gotchas的出现,您将受益于增加的可测试性和更强的内聚性。此外,还不限于使用枚举、字节、int-short和char表达式作为分支的触发器。

        7
  •  0
  •   Mario Fusco    16 年前

    检查闭包在lambdaj库中的实现方式。实际上,他们的行为与C代表非常相似:

    http://code.google.com/p/lambdaj/wiki/Closures

        8
  •  0
  •   Tirinoarim    8 年前

    可以与静态方法接口。此方法还允许您指定参数。声明接口…

    public interface RouteHandler {
        void handleRequest(HttpExchange t) throws IOException;
    }
    

    还有你的地图…

    private Map<String, RouteHandler> routes = new HashMap<>();
    

    然后实现与接口/参数匹配的静态方法…

    public static void notFound(HttpExchange t) throws IOException {
        String response = "Not Found";
    
        t.sendResponseHeaders(404, response.length());
        OutputStream os = t.getResponseBody();
        os.write(response.getBytes());
        os.close();
    }
    

    然后可以将这些方法添加到地图中…

    routes.put("/foo", CoreRoutes::notFound);
    

    叫他们如下…

    RouteHandler handler = routes.get("/foo");
    handler.handleRequest(exchange);
    
        9
  •  0
  •   tristobal    6 年前

    另一种类似的方法可能是使用Java 8的供应商:

    Map<Integer, Supplier<T> suppliers = new HashMap();
    suppliers.put(1, () -> methodOne());
    suppliers.put(2, () -> methodTwo());
    
    // ...
    
    public T methodOne() { ... }
    public T methodTwo() { ... }
    
    // ...
    
    T obj = suppliers.get(id).run();
    
    推荐文章