java - 使用 Java 反射处理事件

标签 java reflection event-handling

好吧,这解释起来很困惑。我会尽力的。

受到 Bukkit 事件系统的启发,您只需使用 @EventHandler 即可使事件处理程序无效。

示例:

@EventHandler
public void aRandomName(PlayerMoveEvent ev) {

}

如您所见,方法的名称并不重要。传递哪个事件由事件参数类型决定。

所有事件都扩展Event类。 我编写了一些我认为可以工作的代码,除了一件事。

public List<Object> eventContainers;

public void fireEvent(Event e) {

    Method[] methods;

    for (Object o : eventContainers) {
        Object[] classes = o.getClass().getClasses();

        for (Object clss : classes) {
            methods = clss.getClass().getMethods();
            for (Method m : methods) {
                if (m.getAnnotation(EventHandler.class) != null) {
                    try {
                        Class[] requiredTypes = m.getParameterTypes();
                        for(Class cl : requiredTypes) {
                            if(e.equals(cl)) {
                                m.invoke(clss, e);
                            }
                        }

                    } catch (IllegalAccessException ex) {
                    } catch (IllegalArgumentException ex) {
                    } catch (InvocationTargetException ex) {
                    }
                }
            }
        }
    }
}

我的代码的作用: 循环遍历 eventContainers 中的所有类,查找具有 @EventHandler 注释的方法,并将指定的事件发送到该方法。但是,我想查看 fireEvent(Event e) 中的给定事件是什么类型的事件,然后查看需要该类型事件参数的方法。我该怎么做呢?我认为

Class[] requiredTypes = m.getParameterTypes();
for(Class cl : requiredTypes) {
  if(e.equals(cl)) {
    m.invoke(clss, e);
  }
}

不会工作。

最终我希望能够将事件传递给插件。像这样:

EventManager.fireEvent(new PlayerMoveEvent(player));

这将被发送到所有插件以及具有

@EventHandler
public void aVoid(PlayerMoveEvent e) {
//stuff
}

如果您有任何疑问,我会尽力解释得更好。预先感谢您的帮助!

最佳答案

您的代码使用 e.equals(cl),它将 Event 的实例与 Class 的实例( Event 的实例) - 这永远不会返回 true。您想做的是:

if(e.getClass().equals(cl)) {
    m.invoke(clss, e);
}

或者,如果您希望使用 @EventHandler 注解的方法来处理其方法签名定义的类的所有子类(即像 handle(Event e) 这样的方法将被 PlayerMoveEvents 以及所有其他事件调用),那么你想要:

if(cl.isAssignableFrom(e.getClass())) {
    m.invoke(clss, e);
}

请参阅Class Javadoc here了解更多信息。

请注意,我认为您的代码中还存在一些其他问题。例如,应使用包含用 @EventHandler 注解的方法的类实例来调用 Method.invoke。您的代码有点不清楚,但我相信这应该是:

m.invoke(o, e);

此外,通过调用 o.getClass().getClasses(),您正在迭代 o 类中定义的类 - 您可能想要迭代直接使用o类的方法,即:

for (Method m : o.getClass().getMethods()) {
    if (m.getAnnotation(EventHandler.class) != null) {
        Class[] requiredTypes = m.getParameterTypes();
        if (requiredTypes.length == 1 && requiredTypes[0].isAssignableFrom(e.getClass()) {
            m.invoke(o, e);
        }
    }
}

关于java - 使用 Java 反射处理事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18471631/

相关文章:

Java:为线程池中的线程设置超时

java - 接口(interface)实现

pointers - 确认 Go 中的结构字段非零

c# - 由于反射访问私有(private)字段和属性不是安全问题吗?

javascript - 监听已检查的输入 ="checkbox"并为输入 ="text"分配等百分比的 Javascript Jquery 事件

javascript - 如何防止在 jquery 中多次注册单个事件处理程序

java - Hibernate 不填充连接表

java - 有谁知道为什么我会收到以下错误? : Syntax error on token(s), 结构错位

c# - 如何在反射中使用不完整的类型?

javascript - jQuery 单击处理程序在多次单击后运行缓慢