使用java反射调用匿名类的方法时访问异常

时间:2010-04-17 18:38:43

标签: java events reflection anonymous-class access-levels

我正在尝试使用事件调度程序来允许模型在订阅的侦听器发生更改时通知它。事件调度程序接收在调度期间调用的处理程序类和方法名称。演示者订阅模型更改并提供要在更改时调用的Handler实现。

这是代码(对不起,有点长)。

EventDispacther:

package utils;

public class EventDispatcher<T> {
    List<T> listeners;
    private String methodName;

    public EventDispatcher(String methodName) {
        listeners = new ArrayList<T>();
        this.methodName = methodName;
    }

    public void add(T listener) {
        listeners.add(listener);
    }

    public void dispatch() {
        for (T listener : listeners) {
            try {
                Method method = listener.getClass().getMethod(methodName);
                method.invoke(listener);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
    }
}

型号:

package model;

public class Model {
    private EventDispatcher<ModelChangedHandler> dispatcher;

    public Model() {
        dispatcher = new EventDispatcher<ModelChangedHandler>("modelChanged");
    }

    public void whenModelChange(ModelChangedHandler handler) {
        dispatcher.add(handler);
    }

    public void change() {
        dispatcher.dispatch();
    }
}

ModelChangedHandler:

package model;

public interface ModelChangedHandler {
    void modelChanged();
}

主讲人:

package presenter;

public class Presenter {

    private final Model model;

    public Presenter(Model model) {
        this.model = model;
        this.model.whenModelChange(new ModelChangedHandler() {

            @Override
            public void modelChanged() {
                System.out.println("model changed");
            }
        });
    }
}

主:

package main;

public class Main {
    public static void main(String[] args) {
        Model model = new Model();
        Presenter presenter = new Presenter(model);
        model.change();
    }
}

现在,我希望得到“模型已更改”的消息。但是,我得到一个java.lang.IllegalAccessException:类utils.EventDispatcher无法使用修饰符“public”访问类presenter.Presenter $ 1的成员。

我明白应该责怪的是我在演示者中创建的匿名课程,但是我不知道如何让它比现在更加“公开”。如果我用命名的嵌套类替换它,它似乎工作。如果Presenter和EventDispatcher在同一个包中,它也可以工作,但我不能允许(不同包中的几个演示者应该使用EventDispatcher)

任何想法?

3 个答案:

答案 0 :(得分:10)

这是JVM(bug 4819108

中的错误

解决方法是在致电method.setAccessible(true)

之前致电method.invoke(listener)

答案 1 :(得分:1)

我的猜测是匿名类始终是private,但我没有在Java语言规范中找到关于此的明确声明(我查看了§15.9.5)

在Java中,如果某个类型不可访问,则其成员也不可访问。

如果你喜欢黑魔法,你可以使用method.setAccessible(true)禁用访问检查。或者,您可以要求将事件处理程序命名为类,或者以可访问类型声明相关方法。

答案 2 :(得分:0)

在这种情况下使用反射是一个非常糟糕的主意。只需让您的调度员调用所需的方法即可。如果您需要多个调度程序来调用不同的方法,只需将它们子类化即可。

Java缺少闭包,但帮助正在进行中!