为什么我的 isAnnotationPresent 方法不起作用,即使注释具有 RetentionPolicy.RUNTIME?
Why is my isAnnotationPresent method not working eventhough the Annotation has a RetentionPolicy.RUNTIME?
我正在尝试为我的 OpenGL 游戏引擎实现一个基于注释的事件系统。我在我想这样调用的方法上应用了 @EventListener 注释:
@EventListener(type = Type.COLLISION)
public void OnCollision(CollisionEvent data)
{
System.out.println("HI");
}
此方法所在的 class 实现了一个空接口:
public class Sprite implements EventHandler
EventDispatcher class:
public class EventDispatcher
{
private static List<EventHandler> registered = new ArrayList<EventHandler>();
public static void register(EventHandler EventHandler)
{
if (!registered.contains(EventHandler))
{
registered.add(EventHandler);
}
}
public static void unregister(EventHandler EventHandler)
{
if (registered.contains(EventHandler))
{
registered.remove(EventHandler);
}
}
public static List<EventHandler> getRegistered()
{
return registered;
}
public static void dispatch(final Event event)
{
new Thread()
{
@Override
public void run()
{
call(event);
}
}.start();
}
private static void call(final Event event)
{
for (EventHandler registered : getRegistered())
{
Method[] methods = registered.getClass().getMethods();
for (int i = 0; i < methods.length; i++)
{
System.out.println("Annotation Being Checked");
if (methods[i].isAnnotationPresent(EventListener.class))
{
System.out.println("Has Annotation");
Class<?>[] methodParams = methods[i].getParameterTypes();
if (methodParams.length < 1)
{
continue;
}
if (!event.getClass().getSimpleName().equals(methodParams[0].getSimpleName()))
{
continue;
}
try
{
methods[i].invoke(registered.getClass().newInstance(), event);
} catch (Exception exception)
{
System.err.println(exception);
}
} else System.out.println("No Annotation");
}
}
}
}
但是当我运行这个程序时,它总是打印出来
正在检查注释
无注释
多次。
有人可以帮忙吗?如果需要更多信息,请询问,我将编辑问题。
我根据您的示例设置了一个项目,并且运行良好。但是,当您的代码评估 Sprite
事件处理程序的所有方法时,您会看到一些 "No Annotation" 消息。即使您没有实现除 OnCollision
之外的任何其他方法,每个 class 都将从 Object 继承默认方法,例如 equals
、hashCode
或 toString
。
测试class:
public class SpriteTest {
public static void main(String[] args) {
EventDispatcher.register(new Sprite());
CollisionEvent collisionEvent = new CollisionEvent();
EventDispatcher.dispatch(collisionEvent);
}
}
除此之外,您的代码中还有一些明显的缺陷:
- 不要使用有状态静态成员 (EventDispatcher.registered),除非您知道自己在做什么并且了解随之而来的多线程方面
- 您存储
EventHandler
的实例,但仅使用 class 信息并动态创建一个新实例 - 为什么不注册 class 而不是直接注册实例
- 您为每个要分派的事件创建了新的线程。这是非常糟糕的做法,因为线程创建是一项代价高昂的操作。改为使用线程池并提交可运行对象或可调用对象
- 您检查 class' 简单名称是否匹配以查看处理程序方法是否适用。这在使用继承时会中断,应替换为
Class.isAssignableFrom
- 这里注释的一般用法是有问题的。您最好为不同的事件类型使用专用接口。而不是通用
EventHandler
可能有 CollisionEventHandler
等等...
粗略的实现思路
public interface CollisionEventHandler extends EventHandler {
void onCollision(CollisionEvent event);
}
public class Sprite implements CollisionEventHandler {
public void onCollision(CollisionEvent data) {
System.out.println("HI");
}
}
public class EventDispatcher {
...
static void call(final CollisionEvent event) {
getRegistered().stream()
.filter(handler -> handler instanceof CollisionEventHandler)
.map(handler -> (CollisionEventHandler) handler)
.forEach(handler -> handler.onCollision(event));
}
}
要处理不同类型的事件,您将需要不同的 call/dispatch 方法。也许你可以使用 Visitor pattern(虽然我不喜欢它)。
我正在尝试为我的 OpenGL 游戏引擎实现一个基于注释的事件系统。我在我想这样调用的方法上应用了 @EventListener 注释:
@EventListener(type = Type.COLLISION)
public void OnCollision(CollisionEvent data)
{
System.out.println("HI");
}
此方法所在的 class 实现了一个空接口:
public class Sprite implements EventHandler
EventDispatcher class:
public class EventDispatcher
{
private static List<EventHandler> registered = new ArrayList<EventHandler>();
public static void register(EventHandler EventHandler)
{
if (!registered.contains(EventHandler))
{
registered.add(EventHandler);
}
}
public static void unregister(EventHandler EventHandler)
{
if (registered.contains(EventHandler))
{
registered.remove(EventHandler);
}
}
public static List<EventHandler> getRegistered()
{
return registered;
}
public static void dispatch(final Event event)
{
new Thread()
{
@Override
public void run()
{
call(event);
}
}.start();
}
private static void call(final Event event)
{
for (EventHandler registered : getRegistered())
{
Method[] methods = registered.getClass().getMethods();
for (int i = 0; i < methods.length; i++)
{
System.out.println("Annotation Being Checked");
if (methods[i].isAnnotationPresent(EventListener.class))
{
System.out.println("Has Annotation");
Class<?>[] methodParams = methods[i].getParameterTypes();
if (methodParams.length < 1)
{
continue;
}
if (!event.getClass().getSimpleName().equals(methodParams[0].getSimpleName()))
{
continue;
}
try
{
methods[i].invoke(registered.getClass().newInstance(), event);
} catch (Exception exception)
{
System.err.println(exception);
}
} else System.out.println("No Annotation");
}
}
}
}
但是当我运行这个程序时,它总是打印出来
正在检查注释
无注释
多次。
有人可以帮忙吗?如果需要更多信息,请询问,我将编辑问题。
我根据您的示例设置了一个项目,并且运行良好。但是,当您的代码评估 Sprite
事件处理程序的所有方法时,您会看到一些 "No Annotation" 消息。即使您没有实现除 OnCollision
之外的任何其他方法,每个 class 都将从 Object 继承默认方法,例如 equals
、hashCode
或 toString
。
测试class:
public class SpriteTest {
public static void main(String[] args) {
EventDispatcher.register(new Sprite());
CollisionEvent collisionEvent = new CollisionEvent();
EventDispatcher.dispatch(collisionEvent);
}
}
除此之外,您的代码中还有一些明显的缺陷:
- 不要使用有状态静态成员 (EventDispatcher.registered),除非您知道自己在做什么并且了解随之而来的多线程方面
- 您存储
EventHandler
的实例,但仅使用 class 信息并动态创建一个新实例 - 为什么不注册 class 而不是直接注册实例 - 您为每个要分派的事件创建了新的线程。这是非常糟糕的做法,因为线程创建是一项代价高昂的操作。改为使用线程池并提交可运行对象或可调用对象
- 您检查 class' 简单名称是否匹配以查看处理程序方法是否适用。这在使用继承时会中断,应替换为
Class.isAssignableFrom
- 这里注释的一般用法是有问题的。您最好为不同的事件类型使用专用接口。而不是通用
EventHandler
可能有CollisionEventHandler
等等...
粗略的实现思路
public interface CollisionEventHandler extends EventHandler {
void onCollision(CollisionEvent event);
}
public class Sprite implements CollisionEventHandler {
public void onCollision(CollisionEvent data) {
System.out.println("HI");
}
}
public class EventDispatcher {
...
static void call(final CollisionEvent event) {
getRegistered().stream()
.filter(handler -> handler instanceof CollisionEventHandler)
.map(handler -> (CollisionEventHandler) handler)
.forEach(handler -> handler.onCollision(event));
}
}
要处理不同类型的事件,您将需要不同的 call/dispatch 方法。也许你可以使用 Visitor pattern(虽然我不喜欢它)。