java - 为什么即使注释有 RetentionPolicy.RUNTIME,我的 isAnnotationPresent 方法也不起作用?

标签 java events system

我正在尝试为我的 OpenGL 游戏引擎实现基于注释的事件系统。我在我想要这样调用的方法上应用 @EventListener 注解:

@EventListener(type = Type.COLLISION)
public void OnCollision(CollisionEvent data)
{
    System.out.println("HI");
}

该方法所在的类实现了一个空接口(interface):

public class Sprite implements EventHandler

EventDispatcher 类:

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 事件处理程序的所有方法时,您会看到一些“无注释”消息。即使您没有实现除 OnCollision 之外的任何其他方法,每个类也会从 Object 继承默认方法,例如 equalshashCodetoString

测试类:

public class SpriteTest {

    public static void main(String[] args) {
        EventDispatcher.register(new Sprite());

        CollisionEvent collisionEvent = new CollisionEvent();
        EventDispatcher.dispatch(collisionEvent);
    }
}



除此之外,您的代码中还存在一些明显的缺陷:

  • 不要使用有状态静态成员 (EventDispatcher.registered),除非您知道自己在做什么并且了解随之而来的多线程方面
  • 您存储 EventHandler 的实例,但仅使用类信息并动态创建新实例 - 为什么不直接注册类而不是实例
  • 您为每个要分派(dispatch)的事件创建新线程。这是非常糟糕的做法,因为创建线程是一项成本高昂的操作。使用线程池来代替并提交可运行或可调用
  • 您检查类的简单名称是否匹配,以查看处理程序方法是否适用。使用继承时这会中断,应替换为 Class.isAssignableFrom
  • 这里注释的一般用法是有问题的。您最好为不同的事件类型使用专用接口(interface)。可以使用 CollisionEventHandler 来代替通用的 EventHandler 等等...

粗略的实现思路

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

要处理不同类型的事件,您将需要不同的调用/调度方法。也许你可以使用 Visitor pattern (虽然我不喜欢它)。

关于java - 为什么即使注释有 RetentionPolicy.RUNTIME,我的 isAnnotationPresent 方法也不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58678031/

相关文章:

c++ - 运行外部程序并获取返回的整数

java - 使用 Android 应用登录 Twitter 失败并出现授权错误

jquery - Meteor ,使用 jquery sortable 导致模板未绑定(bind)

java - 访问存储在 .jar 中的 PDF 文件

java - 即使我有监听器和@EvenHandler,为什么事件没有被激活?

c# - 分离事件 (C#)

java - System.nanoTime 的准确度应该如何? - java

c - 系统函数调用异步?

java - 下面的代码问题解决方案在本地 IDE 中对我有用,但在 Hackerrank IDE 中以某种方式失败,我的代码是否有任何问题

java - 没有主要 list 属性 - IntelliJ