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

2022-08-31 21:02:59

我有两个类:

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

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

我有一个 .如何从 中呼叫?基本上,与从 调用相同的效果。BA.method()bsuper.method()B

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);

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


答案 1

如果您使用的是 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";
  }
}

答案 2

基于@java4script的答案,我注意到如果你试图从子类之外(即,你通常会从开头调用的地方)来做这个技巧,你会得到一个。该方法仅允许您在某些情况下绕过此操作(例如,当您从 与 和 相同的包调用时)。我为一般情况找到的唯一解决方法是极端(并且显然不可移植)的黑客攻击:IllegalAccessExceptionsuper.toString()inBaseSub

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()));
    }
}

印刷

Sub
Base