1

好的,这很难解释。我会尽力。

受 Bukkit 事件系统的启发,您可以通过使用 @EventHandler 使 voids 成为事件处理程序。

例子:

@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
}

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

4

4 回答 4

0

您可以从Methodusing获取参数类型method.getGenericParameterTypes(),因此:

m.invoke(clss, m.getGenericParameterTypes()[0].class.cast(e));

不确定这是否是您想要的。

于 2013-08-27T17:30:40.627 回答
0

假设EventHandler注解的方法只有一个参数

Method[] methods = YourClass.class.getDeclaredMethods();
Object yourInstance = null; // get it
Event e = null; // get it
for (Method method : methods) {
    EventHandler handler = method.getAnnotation(EventHandler.class);
    if (handler != null) {
        Class<?>[] parameterTypes = method.getParameterTypes();
        // you're going to need different logic if you have more than one parameter
        if (parameterTypes.length == 1 && parameterTypes[0].isAssignableFrom(e.getClass())) {
            method.invoke(yourInstance, e);
        }
    }
}

我没有包括任何异常处理。

获取事件处理程序候选类的所有方法并对其进行迭代。如果方法有@EventHandler注解,则获取其参数类型列表。如果它只有一个参数并且该类型可以从您的事件类型中分配e.getClass(),则在您的事件中调用它。

于 2013-08-27T17:35:59.490 回答
0

您的代码使用e.equals(cl),它将 的实例EventClass(的实例的类)的实例进行比较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 。

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

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);
        }
    }
}
于 2013-08-27T17:43:01.853 回答
0

我现在已将代码修改为工作事件系统!!!!!!:D 非常感谢安德舒勒!

public void fireEvent(Event e) {

    Method[] methods;

    for (Object o : eventContainers) {
        methods = o.getClass().getMethods();
        for (Method m : methods) {
            if (m.getAnnotation(EventHandler.class) != null) {
                try {

                    if (m.getParameterTypes()[0].isAssignableFrom(e.getClass())) {
                        m.invoke(o, e);
                    }
                } catch (IllegalAccessException ex) {
                } catch (IllegalArgumentException ex) {
                } catch (InvocationTargetException ex) {
                }
            }
        }
    }
}

我记住了所有答案,谢谢大家!

于 2013-08-27T17:57:24.277 回答