我读了这个问题,并认为如果有人可以这样写,这个问题就很容易解决(并不是说没有它就不能解决):
@Override
public String toString() {
return super.super.toString();
}
我不确定它在很多情况下是否有用,但我想知道为什么它没有,以及其他语言中是否存在类似的东西。
你们怎么看?
编辑:
澄清一下:是的,我知道,这在Java中是不可能的,我并不真的怀念它。这不是我期望的工作,并惊讶地得到一个编译器错误。我只是有了个想法,喜欢讨论一下。
当你不能改变基类的代码时,调用super.super.method()是有意义的。这通常发生在扩展现有库时。
首先问问自己,为什么要扩展这个类?如果答案是“因为我不能改变它”,那么你可以在你的应用程序中创建确切的包和类,并重写调皮方法或创建委托:
package com.company.application;
public class OneYouWantExtend extends OneThatContainsDesiredMethod {
// one way is to rewrite method() to call super.method() only or
// to doStuff() and then call super.method()
public void method() {
if (isDoStuff()) {
// do stuff
}
super.method();
}
protected abstract boolean isDoStuff();
// second way is to define methodDelegate() that will call hidden super.method()
public void methodDelegate() {
super.method();
}
...
}
public class OneThatContainsDesiredMethod {
public void method() {...}
...
}
例如,您可以创建org.springframework.test.context.junit4。类SpringJUnit4ClassRunner,所以这个类应该在jar中真正的类之前加载。然后重写方法或构造函数。
注意:这是绝对的黑客,强烈不建议使用,但它是工作!使用这种方法是危险的,因为类装入器可能存在问题。此外,这可能会导致问题,每次您将更新库包含覆盖类。
我认为以下代码允许在大多数情况下使用super.super…super.method()。
(即使这样做很难看)
简而言之
创建祖先类型的临时实例
将字段值从原始对象复制到临时对象
在临时对象上调用目标方法
将修改后的值复制回原始对象
用法:
public class A {
public void doThat() { ... }
}
public class B extends A {
public void doThat() { /* don't call super.doThat() */ }
}
public class C extends B {
public void doThat() {
Magic.exec(A.class, this, "doThat");
}
}
public class Magic {
public static <Type, ChieldType extends Type> void exec(Class<Type> oneSuperType, ChieldType instance,
String methodOfParentToExec) {
try {
Type type = oneSuperType.newInstance();
shareVars(oneSuperType, instance, type);
oneSuperType.getMethod(methodOfParentToExec).invoke(type);
shareVars(oneSuperType, type, instance);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static <Type, SourceType extends Type, TargetType extends Type> void shareVars(Class<Type> clazz,
SourceType source, TargetType target) throws IllegalArgumentException, IllegalAccessException {
Class<?> loop = clazz;
do {
for (Field f : loop.getDeclaredFields()) {
if (!f.isAccessible()) {
f.setAccessible(true);
}
f.set(target, f.get(source));
}
loop = loop.getSuperclass();
} while (loop != Object.class);
}
}
看看这个Github项目,尤其是objectHandle变量。这个项目展示了如何实际而准确地在孙子上调用祖父母方法。
以防链接被破坏,下面是代码:
import lombok.val;
import org.junit.Assert;
import org.junit.Test;
import java.lang.invoke.*;
/*
Your scientists were so preoccupied with whether or not they could, they didn’t stop to think if they should.
Please don't actually do this... :P
*/
public class ImplLookupTest {
private MethodHandles.Lookup getImplLookup() throws NoSuchFieldException, IllegalAccessException {
val field = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
field.setAccessible(true);
return (MethodHandles.Lookup) field.get(null);
}
@Test
public void test() throws Throwable {
val lookup = getImplLookup();
val baseHandle = lookup.findSpecial(Base.class, "toString",
MethodType.methodType(String.class),
Sub.class);
val objectHandle = lookup.findSpecial(Object.class, "toString",
MethodType.methodType(String.class),
// Must use Base.class here for this reference to call Object's toString
Base.class);
val sub = new Sub();
Assert.assertEquals("Sub", sub.toString());
Assert.assertEquals("Base", baseHandle.invoke(sub));
Assert.assertEquals(toString(sub), objectHandle.invoke(sub));
}
private static String toString(Object o) {
return o.getClass().getName() + "@" + Integer.toHexString(o.hashCode());
}
public class Sub extends Base {
@Override
public String toString() {
return "Sub";
}
}
public class Base {
@Override
public String toString() {
return "Base";
}
}
}
编码快乐! !