Java中的函数指针/委托?

对于我的Java游戏服务器,我发送数据包的Action ID,它基本上告诉服务器数据包的用途。 我想将每个Action ID(一个整数)映射到一个函数。 有没有办法在不使用开关的情况下这样做?

这个如何?

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

(如果需要传递一些参数,请使用具有合适参数的函数定义自己的接口,并使用该参数代替Runnable)。

Java实际上没有函数指针(我们得到了匿名内部类)。 但是,使用交换机确实没有问题,只要你打开值而不是类型。 你有什么理由不想使用开关吗? 看起来您必须在代码中的某个位置执行操作ID和操作之间的映射,那么为什么不保持简单呢?

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

 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 

你有没有用过Swing / AWT? 他们的事件层次结构解决了类似的问题。 例如,Java传递函数的方式是使用接口

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

然后,如果要将整数映射到这些对象上,可以使用java.util.HashMap类的东西来管理它。 实际的实现可以是匿名类(Java的“lambda”的最佳近似值),也可以是某个适当的类。 这是匿名类方式:

 HashMap 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:

 HashMap m = new HashMap() {{ put(0,"hello"); put(1,"world"); }}; 

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

c#delegate(MultiCastDelegate是正确的)从使用MethodInfo方法获取信息,这与使用java.lang.reflect.method为Delegate类做的事情是一样的。 我在本网站的另一种forms上发布了代表(T)类的代码来处理这个extact问题。 我之所以这样做是因为(是的)来自C ++,我需要一种更好的方法来传递函数(尤其是Void),然后必须为函数或更多函数创建一个接口。 现在我可以选择填写参数信息的函数。 Voila`! 很好,可用,没有明显的JIT或JVM速度损失。 如果我只学习了一周的java编程,那么任何java程序员都可以做到。

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

您可以通过使用责任链模式来实现此目的。

它是一种将不同对象链接在一起的模式,就像链接列表一样。 即每个对象在链中都有对next的引用。 链中的对象通常处理一个特定的行为。 对象之间的流程与switch-case语句非常相似。

有一些问题,例如,它将你的逻辑扩散出来,过长的链可能会导致性能问题。 但是,除了这些陷阱之外,您还可以获得更高的可测试性和更强的凝聚力。 此外,您不限于使用enum,byte,int short和char表达式作为分支的触发器。

检查闭包是如何在lambdaj库中实现它们的。 它们实际上具有与C#委托非常相似的行为:

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

您可以接口静态方法。 此方法也允许您指定参数。 声明你的界面……

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

而你的地图……

 private Map routes = new HashMap<>(); 

然后实现匹配interface / params的静态方法……

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