Вызвать абстрактный метод с помощью отражения - PullRequest
0 голосов
/ 11 ноября 2011

У меня есть класс 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 ]

5 голосов
/ 11 ноября 2011
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();
2 голосов
/ 11 ноября 2011

Используйте getMethods вместо getDeclaredMethods.Метод getDeclaredMethods () не возвращает те методы, которые унаследованы, но getMethods () возвращает как объявленные, так и унаследованные.

1 голос
/ 11 ноября 2011

Ваш вопрос показывает, что вы не знаете, как работает полиморфизм. Когда у вас есть ссылка на базовый класс, будь то абстрактный или конкретный, любой метод, вызванный по этой ссылке, будет динамически определять метод, который будет вызываться во время выполнения, на основе фактического объекта. Этот процесс называется динамическим связыванием. Лучше всего, если я покажу простой пример:

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
}

Видите, как тип переменной формы не определяет, какой метод вызывается? Когда мы меняем форму объекта, мы можем изменить вызываемый метод. Тип фигуры определяет только интерфейс, который вы можете использовать для вызова методов. Но фактический тип ссылки, на которую он указывает, определяет, какой метод вызывается.

Так что это длинный ответ на вопрос, почему вам не нужно использовать отражение для вызова этого метода в абстрактном классе. Просто используйте полиморфизм, и он вызовет правильный метод «волшебным образом».

1 голос
/ 11 ноября 2011

Предположительно, вы можете получить Class<? extends SomeTaskManager> для c с SomeTaskManager.class.Вы не должны использовать c в качестве экземпляра, это класс.Вам нужно создать новый экземпляр SomeTaskManager и использовать его.

Вы не можете создать экземпляр абстрактного класса с абстрактными методами.Вы должны реализовать эти методы в подклассе и создать его экземпляр.

...