Как вызвать метод суперкласса с использованием рефлексии в Java
Я сталкиваюсь с проблемой в 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 ответ(ов)
Если вы используете 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
.
Вы не можете сделать этого. Вам нужен экземпляр суперкласса из-за того, как работает диспетчеризация методов в 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
.
Вы не можете сделать это. Это означало бы, что полиморфизм не работает.
Вам нужен экземпляр класса A
. Вы можете создать его с помощью superclass.newInstance()
, а затем передать все поля с помощью чего-то вроде BeanUtils.copyProperties(..)
(из библиотеки commons-beanutils). Однако это всего лишь "хаки" — вам следует улучшить свой дизайн, чтобы избежать необходимости в этом.
Я не знаю, как это сделать в случае, когда вы хотите применить этот трюк для включенных библиотек, поскольку рефлексия не работает, но для своего собственного кода я бы использовал такой простой способ:
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 потребует слишком много неаккуратного кода 😃
Ошибка «Необходимо переопределить метод суперкласса» после импорта проекта в Eclipse
Как создать обобщённый массив в Java?
Получить обобщённый тип класса во время выполнения
Какие проблемы следует учитывать при переопределении equals и hashCode в Java?
Выполнение кода, содержащегося в строке