如何使用Java反射调用超类方法

Ted*_*Ted 43 java reflection overriding superclass

我有两节课.

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

public class B extends A {
    @Override
    public Object method() {...}
}
Run Code Online (Sandbox Code Playgroud)

我有一个B的实例.如何从b调用A.method()?基本上,与从B调用super.method()的效果相同.

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

但是上面的代码仍然会调用B.method()

jav*_*ipt 27

如果您使用的是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()));   // outputs Base
    System.out.println(h2.invoke(new Test()));   // outputs Base
  }

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

}

class Base {
  @Override
  public String toString() {
    return "Base";
  }
}
Run Code Online (Sandbox Code Playgroud)


Gre*_*reg 10

这是不可能的.java中的方法调度始终考虑对象的运行时类型,即使使用反射也是如此.请参阅Method.invokejavadoc ; 特别是这一节:

如果底层方法是实例方法,则使用动态方法查找调用它,如Java语言规范,第二版,第15.12.4.4节中所述; 特别是,将发生基于目标对象的运行时类型的覆盖.

  • 但是super.method()如何工作?我相信JVM同时拥有A.method和B.method字节码,如果B.method调用super.method(),它会选择调用A.method(). (3认同)

Jes*_*ick 7

对@ java4script的答案的基础上,我注意到,你得到的IllegalAccessException,如果你尝试从做这一招之外的子类(即,你通常会调用super.toString()到开始).的in方法,可以仅在某些情况下绕过这个(例如,当你从同一封装调用作为为BaseSub).我发现的一般案例的唯一解决方法是极端(并且明显不可移植)黑客攻击:

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

package p;
public class Sub extends Base {
    @Override public String toString() {
        return "Sub";
    }
}

import p.Base;
import p.Sub;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
public class Demo {
    public static void main(String[] args) throws Throwable {
        System.out.println(new Sub());
        Field IMPL_LOOKUP = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
        IMPL_LOOKUP.setAccessible(true);
        MethodHandles.Lookup lkp = (MethodHandles.Lookup) IMPL_LOOKUP.get(null);
        MethodHandle h1 = lkp.findSpecial(Base.class, "toString", MethodType.methodType(String.class), Sub.class);
        System.out.println(h1.invoke(new Sub()));
    }
}
Run Code Online (Sandbox Code Playgroud)

印花

Sub
Base
Run Code Online (Sandbox Code Playgroud)


Boz*_*zho 3

你不能那样做。这意味着多态性不起作用。

您需要一个A. 您可以创建一个superclass.newInstance(),然后使用类似BeanUtils.copyProperties(..)(来自 commons-beanutils)的内容传输所有字段。但这是一个“黑客”——你应该修复你的设计,这样你就不需要它了。