好吧,这很难解释。我会尽力的。
受Bukkit事件系统的启发,您只需使用@EventHandler就可以使void成为事件处理程序。
示例:
@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(事件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。
请注意,我认为您的代码中还有一些其他问题。例如,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);
}
}
}
您可以使用method.getGenericParameterTypes()
从Method
获取参数类型,因此:
m.invoke(clss, m.getGenericParameterTypes()[0].class.cast(e));
不确定这是否是你想要的。
假设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()
中赋值,那么在您的事件中调用它。
我现在已经将代码修改为工作事件系统!!!!: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) {
}
}
}
}
}
我把所有的答案都记在心里了,谢谢大家!