0

Как вызвать метод суперкласса с использованием рефлексии в Java

10

Я сталкиваюсь с проблемой в Java, связанной с вызовом метода суперкласса. У меня есть два класса:

public class A {
    public Object method() {...}
}

public class B extends A {
    @Override
    public Object method() {...}
}

Я создал экземпляр класса B, и теперь мне нужно вызвать A.method() из экземпляра b. То есть, мне нужно добиться такого же эффекта, как если бы я использовал super.method() внутри класса B.

Вот какой код я использовать:

B b = new B();
Class<?> superclass = b.getClass().getSuperclass();
Method method = superclass.getMethod("method", ArrayUtils.EMPTY_CLASS_ARRAY);
Object value = method.invoke(b, ArrayUtils.EMPTY_OBJECT_ARRAY);

Однако, приведенный выше код по-прежнему вызывает метод B.method(), а не A.method(). Как мне правильно вызвать A.method() из экземпляра B?

4 ответ(ов)

0

Если вы используете JDK7, вы можете использовать MethodHandle для достижения этого результата. Вот пример:

public class Test extends Base {
    public static void main(String[] args) throws Throwable {
        MethodHandle h1 = MethodHandles.lookup().findSpecial(Base.class, "toString",
            MethodType.methodType(String.class),
            Test.class);
        MethodHandle h2 = MethodHandles.lookup().findSpecial(Object.class, "toString",
            MethodType.methodType(String.class),
            Test.class);
        System.out.println(h1.invoke(new Test()));   // выводит Base
        System.out.println(h2.invoke(new Test()));   // выводит Base
    }

    @Override
    public String toString() {
        return "Test";
    }
}

class Base {
    @Override
    public String toString() {
        return "Base";
    }
}

В этом коде вы создаете два MethodHandle: один для метода toString из класса Base и второй для метода toString из класса Object. При вызове этих методов через invoke, оба они возвращают строку "Base", так как MethodHandle действительно вызывает версию метода, реализованную в родительском классе Base. Теперь, если вы хотите получить результат от переопределенного метода toString в классе Test, вам просто нужно использовать invoke для экземпляра Test без указания конкретного MethodHandle.

0

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

Вы могли бы попробовать что-то вроде следующего:

import java.lang.reflect.*;
class A {
    public void method() {
        System.out.println("In a");
    }
}
class B extends A {
    @Override
    public void method() {
        System.out.println("In b");
    }
}
class M {
    public static void main( String ... args ) throws Exception {
        A b = new B();
        b.method();

        b.getClass()
         .getSuperclass()
         .getMethod("method", new Class[]{} )
         .invoke(  b.getClass().getSuperclass().newInstance() ,new Object[]{}  );

    }
}

Однако, скорее всего, это не имеет смысла, потому что вы потеряете данные в b.

0

Вы не можете сделать это. Это означало бы, что полиморфизм не работает.

Вам нужен экземпляр класса A. Вы можете создать его с помощью superclass.newInstance(), а затем передать все поля с помощью чего-то вроде BeanUtils.copyProperties(..) (из библиотеки commons-beanutils). Однако это всего лишь "хаки" — вам следует улучшить свой дизайн, чтобы избежать необходимости в этом.

0

Я не знаю, как это сделать в случае, когда вы хотите применить этот трюк для включенных библиотек, поскольку рефлексия не работает, но для своего собственного кода я бы использовал такой простой способ:

public class A {
    public Object method() {...}
}

public class B extends A {
    @Override
    public Object method() {...}

    public Object methodSuper() {
        return super.method();
    }
}

Для простых случаев это нормально, но для автоматического вызова не очень. Например, когда у вас есть цепочка

A1 супер A2 супер A3 ... супер An 

наследующих классов, все переопределяющих метод m. Тогда вызов метода m из A1 на экземпляре An потребует слишком много неаккуратного кода 😃

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь