变量参数有不同的类型?

时间:2013-11-13 23:19:30

标签: java methods arguments

我的代码中有一个事件监听器列表:

private List<EventListener> listeners = new ArrayList<EventListener>();
listeners.add(new EventListener() {
    @Override
    public void someEvent(String arg1, MyClass arg2) {
        // ...
    }

    @Override
    public void someOtherEvent(AnotherClass arg1, int arg2) {
        // ...
    }
}

目前,我使用for循环调用侦听器:

for (EventListener listener : listeners) {
    listener.someEvent("Hello world", (MyClass) myObject);
}

我想用一种方法来调用它,如下所示:

fireEvent("someEvent", "Hello world", (MyClass) myObject);

或者可能是数组或事件参数的东西。

这样做的一种方法是创建某种事件对象,但我并不特别想这样做,因为它看起来很乱(有人告诉我,如果我在这里错了;我对Java缺乏经验) 。有没有办法创建类似于上面的fireEvent? EventListener是一个接口,如果有帮助的话。

1 个答案:

答案 0 :(得分:1)

理论上,你可以使用java反射来做到这一点:

public void fireEvent(String name, Object... args) {
    Method method = null;
    // 1. find method
    for (Method m : EventListener.class.getMethods()) {
        if (m.getName().equals(name)) {
            method = m;
            break;
        }
    }

    if (method == null) {
        throw new IllegalArgumentException("Unknown event method: " + name);
    }

    // 2. call method on all listeners
    for (EventListener l : listeners) {
        try {
            method.invoke(l, args);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new IllegalArgumentException(e);
        }
    }
}

(请注意,这是一个简单的版本,不包括重载事件方法等所有可能性。)

但我强烈建议不要那样做!它不仅难看且难以阅读,它还使您的程序不再是类型安全的!当您使用错误的名称String或错误的数量或类型的参数时,编译器不会注意到,但程序将在运行时中断!

所以我建议只为侦听器的每个事件处理程序方法使用一个受保护的fireXXXEvent方法(使用简单的for循环)。在你的情况下,这将是:

protected void fireSomeEvent(String arg1, MyClass arg2);
protected void fireSomeOtherEvent(AnotherClass arg1, int arg2);

当然,您也可以引入事件对象(可能通过子类化java.util.EventObject)。但这可能不一定会减少监听器中的方法数量(但它可以 - 取决于您所获得的事件类型)。

有一些更有意思的策略,例如使用带有事件类型对象和泛型事件对象的通用事件处理程序,如JavaFX,但我认为如果您不熟悉Java,则不建议这样做。

旁注:使用CopyOnWriteArrayList存储您的侦听器或在触发事件时迭代listeners的副本,否则如果侦听器尝试触发,您可能会获得ConcurrentModificationException将自己从侦听器列表中删除。