为什么是super.super.method();Java中不允许?

为什么是super.super.method();Java中不允许?,java,superclass,Java,Superclass,我阅读并认为,如果一个人可以写下以下内容,那么这个问题很容易解决(不是说没有它就无法解决): @Override public String toString() { return super.super.toString(); } 我不确定它在很多情况下是否有用,但我想知道为什么不有用,以及在其他语言中是否存在类似的东西 你们觉得怎么样 编辑: 澄清一下:是的,我知道,这在Java中是不可能的,我并不真正怀念它。这并不是我期望的工作,我很惊讶得到一个编译器错误。我刚刚有了这个想法,并

我阅读并认为,如果一个人可以写下以下内容,那么这个问题很容易解决(不是说没有它就无法解决):

@Override
public String toString() {
    return super.super.toString();
}
我不确定它在很多情况下是否有用,但我想知道为什么不有用,以及在其他语言中是否存在类似的东西

你们觉得怎么样

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

我认为如果你覆盖一个方法,并且想要它的所有超类版本(比如说,
等于
),那么你实际上总是想先调用直接超类版本,如果它愿意,它会依次调用它的超类版本

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

this->ReallyTheBase::foo();

它违反了封装。您不应该绕过父类的行为。有时可以绕过自己类的行为(特别是在同一个方法中),但不能绕过父类的行为,这是有道理的。例如,假设我们有一个基本的“项目集合”,一个表示“红色项目集合”的子类和一个表示“大型红色项目集合”的子类。有必要:

public class Items
{
    public void add(Item item) { ... }
}

public class RedItems extends Items
{
    @Override
    public void add(Item item)
    {
        if (!item.isRed())
        {
            throw new NotRedItemException();
        }
        super.add(item);
    }
}

public class BigRedItems extends RedItems
{
    @Override
    public void add(Item item)
    {
        if (!item.isBig())
        {
            throw new NotBigItemException();
        }
        super.add(item);
    }
}
这很好-RedItems可以始终确信它包含的项目都是红色的。现在假设我们能够调用super.super.add():

现在我们可以添加任何我们喜欢的内容,
RedItems
中的不变量被破坏了


这有意义吗?

我猜,因为它不常被使用。我能看到使用它的唯一原因是,如果您的直接上级已覆盖某些功能,而您正试图将其恢复到原始状态


在我看来,这似乎与OO原则背道而驰,因为类的直接父类应该比祖父母更接近您的类。

除了其他人提出的非常好的观点之外,我认为还有另一个原因:如果超类没有超类怎么办

由于每个类都自然地(至少)扩展了
对象
super.whatever()
将始终引用超类中的方法。但是如果您的类只扩展了
对象
,那么
super.super
将指什么呢?应该如何处理这种行为——编译器错误、空指针等


我认为不允许这样做的主要原因是它违反了封装,但这也可能是一个小原因。

我没有足够的声誉发表评论,因此我将把这一点添加到其他答案中

乔恩·斯基特回答得很好,举了一个很好的例子。马特B有一点:并不是所有的超类都有超类。如果你调用了一个没有super的super的super,你的代码就会崩溃

面向对象编程(Java就是这样)是关于对象而不是函数的。如果你想要面向任务的编程,选择C++或其他的东西。如果您的对象不适合它的超类,那么您需要将其添加到“祖父母类”,创建一个新类,或者找到另一个它确实适合的超类


就我个人而言,我发现这种限制是Java最大的优势之一。与我使用过的其他语言相比,代码有点僵硬,但我总是知道会发生什么。这有助于实现Java的“简单和熟悉”目标。在我看来,叫super.super既不简单也不熟悉。也许开发者也有同样的感受

我认为Jon Skeet的答案是正确的。我想补充一点,您可以通过强制转换
this
,从超类的超类访问阴影变量:

interface I { int x = 0; }
class T1 implements I { int x = 1; }
class T2 extends T1 { int x = 2; }
class T3 extends T2 {
        int x = 3;
        void test() {
                System.out.println("x=\t\t"          + x);
                System.out.println("super.x=\t\t"    + super.x);
                System.out.println("((T2)this).x=\t" + ((T2)this).x);
                System.out.println("((T1)this).x=\t" + ((T1)this).x);
                System.out.println("((I)this).x=\t"  + ((I)this).x);
        }
}

class Test {
        public static void main(String[] args) {
                new T3().test();
        }
}
它产生输出:

x= 3 super.x= 2 ((T2)this).x= 2 ((T1)this).x= 1 ((I)this).x= 0 x=3 super.x=2 ((T2)这个)。x=2 ((T1)这个)。x=1 ((I)本条)。x=0 (示例来自


但是,这不适用于方法调用,因为方法调用是根据对象的运行时类型确定的。

似乎至少可以使用反射获取超类的超类的类,尽管不一定是它的实例;如果这可能是有用的,请考虑JavaDoc在

< P>我认为下面的代码允许在大多数情况下使用Super。Suff.Suff.Mult.()。 (即使这样做很难看)

总之

  • 创建祖先类型的临时实例
  • 将字段值从原始对象复制到临时对象
  • 在临时对象上调用目标方法
  • 将修改后的值复制回原始对象
  • 用法:

    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);
        }
    }
    
    公共A类{
    public void doThat(){…}
    }
    公共类B扩展了A{
    public void doThat(){/*不调用super.doThat()*/}
    }
    公共类C扩展到B{
    公共无效doThat(){
    Magic.exec(A.class,this,“doThat”);
    }
    }
    公共课魔术{
    公共静态void exec(类oneSuperType、ChieldType实例、,
    字符串方法(ParentToExec){
    试一试{
    Type Type=oneSuperType.newInstance();
    shareVars(oneSuperType、实例、类型);
    oneSuperType.getMethod(MethodOfParentExec.invoke(类型);
    shareVars(oneSuperType、type、instance);
    }捕获(例外e){
    抛出新的运行时异常(e);
    }
    }
    私有静态void共享变量(类clazz,
    SourceType源,TargetType目标)引发IllegalArgumentException,IllegalAccessException{
    类循环=clazz;
    做{
    for(字段f:loop.getDeclaredFields()){
    如果(!f.isAccessible()){
    f、 setAccessible(true);
    }
    f、 设置(目标,f.get(源));
    }
    loop=loop.getSuperclass();
    }while(循环!=Object.class);
    }
    }
    
    这样做有一些很好的理由。您可能有一个子类w
    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);
        }
    }
    
    public class GrandMa {  
        public void sayYourName(){  
            System.out.println("Grandma Fedora");  
        }  
    }  
    
    public class Mama extends GrandMa {  
        public void sayYourName(boolean lie){  
            if(lie){   
                super.sayYourName();  
            }else {  
                System.out.println("Mama Stephanida");  
            }  
        }  
    }  
    
    public class Daughter extends Mama {  
        public void sayYourName(boolean lie){  
            if(lie){   
                super.sayYourName(lie);  
            }else {  
                System.out.println("Little girl Masha");  
            }  
        }  
    }  
    
    public class TestDaughter {
        public static void main(String[] args){
            Daughter d = new Daughter();
    
            System.out.print("Request to lie: d.sayYourName(true) returns ");
            d.sayYourName(true);
            System.out.print("Request not to lie: d.sayYourName(false) returns ");
            d.sayYourName(false);
        }
    }
    
    public class Foo
    {
      public int getNumber()
      {
        return 0;
      }
    }
    
    public class SuperFoo extends Foo
    {
      public static Foo superClass = new Foo();
      public int getNumber()
      {
        return 1;
      }
    }
    
    public class UltraFoo extends Foo
    {
      public static void main(String[] args)
      {
        System.out.println(new UltraFoo.getNumber());
        System.out.println(new SuperFoo().getNumber());
        System.out.println(new SuperFoo().superClass.getNumber());
      }
      public int getNumber()
      {
        return 2;
      }
    }
    
    2
    1
    0
    
    public class A {
    
         @Override
         public String toString() {
              return "A";
         }
    
    }
    
    
    public class B extends A {
    
         @Override
         public String toString() {
              return "B";
         }
    
    }
    
    public class C extends B {
    
         @Override
         public String toString() {
              return "C";
         }
    
    }
    
    
    public class D extends C {
    
         @Override
         public String toString() {
              String result = "";
              try {
                    result = this.getClass().getSuperclass().getSuperclass().getSuperclass().newInstance().toString();
              } catch (InstantiationException ex) {
                    Logger.getLogger(D.class.getName()).log(Level.SEVERE, null, ex);
              } catch (IllegalAccessException ex) {
                    Logger.getLogger(D.class.getName()).log(Level.SEVERE, null, ex);
              }
              return result;
         }
    
    }
    
    public class Main {
    
         public static void main(String... args) {
              D d = new D();
              System.out.println(d);
    
         }
    }
    
    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() {...}
        ...
    }
    
            ...
            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(...);
                           }
            }
    
    public class A {
        protected void printClass() {
            System.out.println("In A Class");
        }
    }
    
    public class B extends A {
    
        @Override
        protected void printClass() {
            if (!(this instanceof C)) {
                System.out.println("In B Class");
            }
            super.printClass();
        }
    }
    
    public class C extends B {
        @Override
        protected void printClass() {
            System.out.println("In C Class");
            super.printClass();
        }
    }
    
    public class Driver {
        public static void main(String[] args) {
            C c = new C();
            c.printClass();
        }
    }
    
    In C Class
    In A Class
    
    class SuperSuperClass {
        public String toString() {
            return DescribeMe();
        }
    
        protected String DescribeMe() {
            return "I am super super";
        }
    }
    
    class SuperClass extends SuperSuperClass {
        public String toString() {
            return "I am super";
        }
    }
    
    class ChildClass extends SuperClass {
        public String toString() {
            return DescribeMe();
        }
    }
    
    class SuperSuperClass {
        public String toString() {
            return "I am super super";
        }
    }
    
    class SuperClass extends SuperSuperClass {
        public String toString() {
            return DescribeMe(super.toString());
        }
    
        protected String DescribeMe(string fromSuper) {
            return "I am super";
        }
    }
    
    class ChildClass extends SuperClass {
        protected String DescribeMe(string fromSuper) {
            return fromSuper;
        }
    }
    
    new ChildClass().toString();
    
    public abstract class A {
    
        public void methodName() {
            System.out.println("Class A");
        }
    
    }
    
    public class B extends A {
    
        public void methodName() {
            super.methodName();
            System.out.println("Class B");
        }
    
        // Will call the super methodName
        public void hackSuper() {
            super.methodName();
        }
    
    }
    
    public class C extends B {
    
        public static void main(String[] args) {
            A a = new C();
            a.methodName();
        }
    
        @Override
        public void methodName() {
            /*super.methodName();*/
            hackSuper();
            System.out.println("Class C");
        }
    
    }
    
    public class SubSubClass extends SubClass {
    
        @Override
        public void print() {
            super.superPrint();
        }
    
        public static void main(String[] args) {
            new SubSubClass().print();
        }
    }
    
    class SuperClass {
    
        public void print() {
            System.out.println("Printed in the GrandDad");
        }
    }
    
    class SubClass extends SuperClass {
    
        public void superPrint() {
            super.print();
        }
    }
    
    public class A
        internal virtual void foo()
    ...
    public class B : A
        public new void foo()
    ...
    public class C : B
        public new void foo() {
           (this as A).foo();
        }
    
    type
       A=class
          procedure foo;
          ...
       B=class(A)
         procedure foo; override;
         ...
       C=class(B)
         procedure foo; override;
         ...
    A(objC).foo();
    
    class A {               
       int y=10;            
    
       void foo(Class X) throws Exception {  
          if(X!=A.class)
             throw new Exception("Incorrect parameter of "+this.getClass().getName()+".foo("+X.getName()+")");
          y++;
          System.out.printf("A.foo(%s): y=%d\n",X.getName(),y);
       }
       void foo() throws Exception { 
          System.out.printf("A.foo()\n");
          this.foo(this.getClass()); 
       }
    }
    
    class B extends A {     
       int y=20;            
    
       @Override
       void foo(Class X) throws Exception { 
          if(X==B.class) { 
             y++; 
             System.out.printf("B.foo(%s): y=%d\n",X.getName(),y);
          } else { 
             System.out.printf("B.foo(%s) calls B.super.foo(%s)\n",X.getName(),X.getName());
             super.foo(X);
          } 
       }
    }
    
    class C extends B {     
       int y=30;            
    
       @Override
       void foo(Class X) throws Exception { 
          if(X==C.class) { 
             y++; 
             System.out.printf("C.foo(%s): y=%d\n",X.getName(),y);
          } else { 
             System.out.printf("C.foo(%s) calls C.super.foo(%s)\n",X.getName(),X.getName());
             super.foo(X);
          } 
       }
    
       void DoIt() {
          try {
             System.out.printf("DoIt: foo():\n");
             foo();         
             Show();
    
             System.out.printf("DoIt: foo(B):\n");
             foo(B.class);  
             Show();
    
             System.out.printf("DoIt: foo(A):\n");
             foo(A.class);  
             Show();
          } catch(Exception e) {
             //...
          }
       }
    
       void Show() {
          System.out.printf("Show: A.y=%d, B.y=%d, C.y=%d\n\n", ((A)this).y, ((B)this).y, ((C)this).y);
       }
    } 
    
    DoIt: foo():
    A.foo()
    C.foo(C): y=31
    Show: A.y=10, B.y=20, C.y=31
    
    DoIt: foo(B):
    C.foo(B) calls C.super.foo(B)
    B.foo(B): y=21
    Show: A.y=10, B.y=21, C.y=31
    
    DoIt: foo(A):
    C.foo(A) calls C.super.foo(A)
    B.foo(A) calls B.super.foo(A)
    A.foo(A): y=11
    Show: A.y=11, B.y=21, C.y=31
    
    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";
            }
        }
    }
    
    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();
        }
    }