使用调用动态方法时出现IllegalAccessException

时间:2011-05-28 12:58:44

标签: java reflection

我正在尝试在Java中使用Reflection但我得到一个奇怪的错误。当我收到错误消息时会出现什么问题:

java.lang.IllegalAccessException: Class com.myapp.core.utils.EventDispatcher can not access a member of class appApp$1 with modifiers "public"
at sun.reflect.Reflection.ensureMemberAccess(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)

我只是尝试创建自己的EventDispatcher类,在其中,我使用反射的部分,也是导致问题的代码行:

public void dispatchEvent(Event e, String callMethName) {
IEventListener list = ((IEventListener)listeners[i]);
                list.getClass().getMethod(callMethName, Event.class).invoke(list, e);
}

在我的主类上,我有一些调用addListener的东西,它只会将监听器添加到EventDispatcher类的列表中:

try {
obj.addListener("onTestHandler", new MyTestEventListener(){
    @Override
    public void onTestHandler(Event e) {
        System.out.println("hello!");
    }
});
} catch (SecurityException e) {
    e.printStackTrace();
}

因此,第一个表示“onTestHandler”的参数将传递给EventDispatcher类,并最终作为dispatchEvent方法中参数callMethName的一部分,该方法将动态调用该方法。

传递方法和一切都是正确的。它是反射某种方式存在问题的部分。它似乎能够找到这种方法。但由于某种原因,抛出IllegalAccessException并且无法调用该方法。

为什么会这样?

感谢。

2 个答案:

答案 0 :(得分:16)

我怀疑实现appApp$1的匿名类(MyTestEventListener)具有包可见性,反射代码位于另一个包中。

对于此代码:

package foo.p1;
public class Target {
  public static interface Foo {
    public void bar();
  }

  public static Foo newFoo() {
    return new Foo() {
      @Override
      public void bar() { 
      }
    };
  }
}

此代码将失败,因为newFoo()返回的运行时类型不是公共类:

package foo.p2;
import foo.p1.Target;
public class Main {
  public static void main(String[] args) throws Exception {
    Target.Foo foo = Target.newFoo();
    foo.getClass()
        .getMethod("bar")
        .invoke(foo);
  }
}

可以通过将方法设置为可访问来解决此问题:

Target.Foo foo = Target.newFoo();
Method m = foo.getClass()
    .getMethod("bar");
m.setAccessible(true);
m.invoke(foo);

或者使用公共接口中的方法:

Target.Foo foo = Target.newFoo();
Target.Foo.class.getMethod("bar")
    .invoke(foo);

答案 1 :(得分:3)

对匿名类的访问是非常严格的..你应该尝试找到具有你想要的方法的对象的非匿名超类或接口,而不是简单地使用list.getClass(),然后调用来自该类的方法而不是匿名方法..

我还建议你在添加监听器并存储结果时进行搜索。使用反射相当昂贵,所以东西运行得更快。同样重要的是,如果您在方法名称中输入拼写错误,则在添加侦听器时会出现错误,而不是在将来的某个随机时间出现错误。以这种方式查找问题会更容易: )