2011-05-28 64 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