通过反射调用抽象方法

时间:2011-11-11 03:31:01

标签: java android reflection abstract-class abstract

我有一个带有抽象方法SomeTaskManager的班级runATask。 我想通过反射执行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)

4 个答案:

答案 0 :(得分: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();

答案 1 :(得分:2)

使用getMethods而不是getDeclaredMethods。 getDeclaredMethods()方法不返回那些继承的方法,但getMethods()返回声明和继承的方法。

答案 2 :(得分:1)

根据Class<? extends SomeTaskManager>,您可以c获得SomeTaskManager.class。您不应该使用c作为实例,它是一个类。您需要创建SomeTaskManager的新实例并使用它。

您无法使用抽象方法创建抽象类的实例。您必须在子类中实现这些方法并实例化它。

答案 3 :(得分: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
}

看看shape变量的类型如何决定调用哪个方法?当我们更改对象形状点时,我们可以更改调用的方法。形状类型仅确定可用于调用方法的接口。但是,它指向的实际参考类型决定了调用哪个方法。

所以这是一个很长的答案,为什么你不需要使用反射来在抽象类上调用该方法。只需使用多态,它就会“神奇地”调用正确的方法。