我读了这个问题,并认为如果有人可以这样写,这个问题就很容易解决(并不是说没有它就不能解决):

@Override
public String toString() {
    return super.super.toString();
}

我不确定它在很多情况下是否有用,但我想知道为什么它没有,以及其他语言中是否存在类似的东西。

你们怎么看?

编辑: 澄清一下:是的,我知道,这在Java中是不可能的,我并不真的怀念它。这不是我期望的工作,并惊讶地得到一个编译器错误。我只是有了个想法,喜欢讨论一下。


当前回答

看看这个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";
        }
    }
}

编码快乐! !

其他回答

这样做有一些很好的理由。你可能有一个子类,它的方法实现不正确,但是父方法实现正确。因为它属于第三方库,所以您可能无法/不愿意更改源代码。在本例中,您希望创建一个子类,但重写一个方法来调用super。超级的方法。

正如其他一些海报所示,通过反射是可以做到这一点的,但应该可以这样做

(本)SuperSuperClass .theMethod ();

我现在正在处理这个问题-快速修复是复制并粘贴超类方法到subsubclass方法:)

我曾经遇到过这样的情况,即体系结构是在一个公共CustomBaseClass中构建公共功能,该CustomBaseClass代表几个派生类实现。 但是,我们需要规避特定派生类的特定方法的通用逻辑。在这种情况下,我们必须使用super.super.methodX实现。

我们通过在CustomBaseClass中引入一个布尔成员来实现这一点,该成员可用于有选择地推迟自定义实现,并在需要时让位于默认框架实现。

        ...
        FrameworkBaseClass (....) extends...
        {
           methodA(...){...}
           methodB(...){...}
        ...
           methodX(...)
        ...
           methodN(...){...}

        }
        /* CustomBaseClass overrides default framework functionality for benefit of several derived classes.*/
        CustomBaseClass(...) extends FrameworkBaseClass 
        {
        private boolean skipMethodX=false; 
        /* implement accessors isSkipMethodX() and setSkipMethodX(boolean)*/

           methodA(...){...}
           methodB(...){...}
        ...
           methodN(...){...}

           methodX(...){
                  if (isSkipMethodX()) {
                       setSKipMethodX(false);
                       super.methodX(...);
                       return;
                       }
                   ... //common method logic
            }
        }

        DerivedClass1(...) extends CustomBaseClass
        DerivedClass2(...) extends CustomBaseClass 
        ...
        DerivedClassN(...) extends CustomBaseClass...

        DerivedClassX(...) extends CustomBaseClass...
        {
           methodX(...){
                  super.setSKipMethodX(true);
                  super.methodX(...);
                       }
        }

然而,在框架和应用程序中遵循良好的架构原则,我们可以通过使用hasA方法而不是isA方法轻松避免这种情况。但在任何时候,期待设计良好的架构都是不现实的,因此需要摆脱坚实的设计原则,引入像这样的技巧。 这只是我的意见……

我认为如果你重写了一个方法,并想要它的所有超类版本(比如,说for equals),那么你实际上总是想先调用直接的超类版本,如果它愿意,后者会依次调用它的超类版本。

我认为这没什么意义(如果有意义的话)。我想不出有什么情况)来调用某个方法的任意超类版本。我不知道这在Java中是否可行。它可以在c++中完成:

this->ReallyTheBase::foo();

关键字super只是在超类中调用方法的一种方法。 在Java教程中:https://docs.oracle.com/javase/tutorial/java/IandI/super.html

如果您的方法覆盖了它的父类的方法之一,您可以通过使用关键字super调用被覆盖的方法。

不要相信这是一个超对象的引用!!不,它只是在超类中调用方法的关键字。

这里有一个例子:

class Animal {
    public void doSth() {
        System.out.println(this);   // It's a Cat! Not an animal!
        System.out.println("Animal do sth.");
    }
}

class Cat extends Animal {
    public void doSth() {
        System.out.println(this);
        System.out.println("Cat do sth.");
        super.doSth();
    }
}

当你调用cat.doSth()时,类Animal中的方法doSth()将打印这个,它是一只猫。

我认为以下代码允许在大多数情况下使用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);
    }
}