2011-11-11 71 views
0

我有一個帶有抽象方法runATask的類SomeTaskManager。 我想通過反射執行runATask方法, 這是我的代碼:我錯過了什麼?通過反思調用抽象方法

SomeTaskManager pm= (SomeTaskManager)context.getSomeTaskManager(); 
Class c = Class.forName(pm.getClass().getName()); 

Method[] allMethods = c.getDeclaredMethods(); 

for (Method m : allMethods) { 
    if (!m.getName().equals("runATask")) { 
     continue; 
    } 
    m.invoke(c ,new Object[] { someParam, null, 1}); 
    break; 
} 

我得到這個錯誤

java.lang.IllegalArgumentException: object is not an instance of the class 
at java.lang.reflect.Method.invokeNative(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:507) 
at de.vogella.android.downloadmanager.DownloadManagerActivity.riflesso(DownloadManagerActivity.java:250) 
at de.vogella.android.downloadmanager.DownloadManagerActivity.onCreate(DownloadManagerActivity.java:68) 
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047) 
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1722) 
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1784) 
at android.app.ActivityThread.access$1500(ActivityThread.java:123) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:939) 
at android.os.Handler.dispatchMessage(Handler.java:99) 
at android.os.Looper.loop(Looper.java:130) 
at android.app.ActivityThread.main(ActivityThread.java:3835) 
at java.lang.reflect.Method.invokeNative(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:507) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:847) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:605) 
+3

什麼問題? –

+1

呃,你不能執行抽象方法 - 沒有什麼可執行的。 –

+0

如果方法在子類中實現,並且在實例化後使用該子類的實例,則可以這樣做。無論如何,你需要向我們展示堆棧跟蹤。我們不知道該方法需要什麼參數,或者您傳遞的參數的類型。此外,你的循環應該處理代碼,找到「runATask」方法然後中斷,而不是跳過那些不是那樣的。這是一個巨大的代碼味道。 –

回答

5
java.lang.IllegalArgumentException: object is not an instance of the class 
    at java.lang.reflect.Method.invoke(Method.java:507) 

啊哈,這裏

m.invoke(c, new Object[] { someParam, null, 1}); 

您傳遞Class,而不是它的一個實例。您需要將pm(具體實例)將其改爲:

m.invoke(pm, new Object[] { someParam, null, 1}); 

這個問題很可能會僅僅閱讀的代碼,如果你採用全和自我記錄的變量名,而不是什麼,說的縮寫越早發現。我也建議在這方面努力。


無關的具體問題,下面一行

Class c = Class.forName(pm.getClass().getName()); 

可以如下

Class c = pm.getClass(); 
+0

問題是,類SomeTaskManager(realy ApplicationPackageManager)不能實例化:直接使用m.invoke(pm,new Object [] {someParam,null,1});我得到java.lang.IllegalArgumentException:對象不是類的一個實例;並使用m.invoke(c.newInstance(),new Object [] {someParam,null,1});我得到java.lang.InstantiationException:android.app.ContextImpl $ ApplicationPackageManager – Zorb

+0

傳遞'pm'應該工作。你是否把班級改爲其他什麼東西?您似乎發佈了不完整的代碼。 – BalusC

1

使用的的getMethods代替getDeclaredMethods。 getDeclaredMethods()方法不返回那些繼承的方法,但getMethods()返回聲明和繼承。

1

想必你可以得到Class<? extends SomeTaskManager>cSomeTaskManager.class簡化。你不應該使用c作爲一個實例,它是一個類。你需要創建一個新的實例SomeTaskManager並使用它。

您不能使用抽象方法創建抽象類的實例。你必須在子類中實現這些方法並實例化它。

1

你的問題表明你不知道多態如何工作。當你有一個基類的引用時,它的抽象或具體,在該引用上調用的任何方法將根據實際對象動態地找出在運行時調用的方法。這個過程被稱爲動態綁定。這是最好的,如果我展示一個簡單的例子:

public class Shape { 
    public void draw() { 
     System.out.println("Draw a Shape"); 
    } 
} 

public class Triangle extends Shape { 
    public void draw() { 
     System.out.println("Draw a Triangle"); 
    } 
} 

public class Square extends Shape { 
    public void draw() { 
     System.out.println("Draw a Square"); 
    } 
} 

所以這個代碼:

public static void main(String[] args) { 
    Shape shape = new Triangle(); 
    shape.draw(); // prints Draw a Triangle 

    shape = new Square(); 
    shape.draw(); // prints Draw a Square 

    shape = new Shape(); 
    shape.draw(); // prints Draw a Shape 
} 

瞭解如何形狀變量的類型並不確定調用哪個方法?當我們改變對象形狀點時,我們可以改變被調用的方法。形狀的類型只決定了你可以用來調用方法的接口。但是,它指向的引用的實際類型決定調用哪個方法。

所以這是一個很長的答案,爲什麼你不需要使用反射來調用抽象類的方法。只要使用多態性,它會「神奇地」調用正確的方法。