2011-05-28 81 views
10

我想在Java中使用反射,但我得到一个奇怪的错误。可能是什么问题时,我得到一个错误,指出:IllegalAccessException当使用调用动态方法

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并且无法调用该方法。

这是为什么?

谢谢。

+1

把所有这些小小的东西缝在一起是相当混乱的。如果你可以提供一个简短的,但是完整的程序来证明这个问题,那么将这些东西分类很容易。它不需要做你的真实应用程序所做的一切 - 仅仅足以证明问题。 – 2011-05-28 13:12:44

+3

有关更多详细信息,请参阅本书[Java Puzzlers](http://www.javapuzzlers.com/)中的益智游戏“Reflection Inflection”。该特定的益智游戏可在[本书的在线样本](http://www.javapuzzlers。COM/Java的谜题 - sampler.pdf)。 – 2011-05-28 13:24:10

+0

感谢Richard,示例章节对理解错误非常有帮助! – Carven 2011-05-28 13:54:07

回答

16

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

对于此代码:

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); 
+0

我一直试图调试这个小时,但没有运气。你刚刚救了我!谢谢!!!! :D – Carven 2011-05-28 13:53:30

+0

使用来自公共接口的方法取得了诀窍,谢谢! – Josejulio 2016-12-06 16:18:40

3

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

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

+0

只是有几个问题,我如何访问非恼人的超类或接口?没有getParent()方法。 另外,您说在添加侦听器时执行搜索。你也指哪个搜索?谢谢! – Carven 2011-05-28 18:54:35