Почему супер.супер.метод (); не разрешено в Java? - PullRequest
337 голосов
/ 25 февраля 2009

Я прочитал этот вопрос и подумал, что его легко решить (а не без него), если бы можно было написать:

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

Я не уверен, что это полезно во многих случаях, но мне интересно , почему это не так, и если что-то подобное существует в других языках.

Что вы, ребята, думаете?

EDIT: Чтобы уточнить: да, я знаю, это невозможно в Java, и я действительно не скучаю по этому. Это ничего, что я ожидал работать, и был удивлен, получив ошибку компилятора. У меня просто была идея, и я хотел бы обсудить ее.

Ответы [ 22 ]

1 голос
/ 26 февраля 2013

У меня были ситуации, подобные этим, когда архитектура заключается в построении общей функциональности в общем 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. Но во все времена не очень практично ожидать хорошо спроектированную архитектуру на месте, и, следовательно, отойти от прочных принципов проектирования и внедрять подобные хаки. Только мои 2 цента ...

1 голос
/ 16 ноября 2011

Вызов 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. Затем перепишите методы или конструкторы.

Внимание: Это абсолютный взлом, и его настоятельно НЕ рекомендуется использовать, но он РАБОТАЕТ! Использование этого подхода опасно из-за возможных проблем с загрузчиками классов. Также это может вызывать проблемы при каждом обновлении библиотеки, содержащей перезаписанный класс.

1 голос
/ 03 июля 2009

Казалось бы, возможно, по крайней мере, получить класс суперкласса суперкласса, хотя не обязательно его экземпляр, используя отражение; если это может быть полезно, пожалуйста, рассмотрите Javadoc в http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getSuperclass()

1 голос
/ 04 сентября 2013

@ Джон Скит Хорошее объяснение. IMO, если кто-то хочет вызвать метод super.super, то нужно игнорировать поведение непосредственного родителя, но хотеть получить доступ к поведению великого родителя. Это может быть достигнуто с помощью. Как показано ниже код

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

В этом случае поведение printClass класса B будет игнорироваться. Я не уверен, является ли это идеальной или хорошей практикой для достижения super.super, но все же это работает.

1 голос
/ 20 июля 2011
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);

     }
}

пробег: СТРОИТЬ УСПЕШНО (общее время: 0 секунд)

0 голосов
/ 27 марта 2011

IMO, это чистый способ достижения super.super.sayYourName() поведения в Java.

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

Выход:

Request to lie: d.sayYourName(true) returns Grandma Fedora
Request not to lie: d.sayYourName(false) returns Little girl Masha

0 голосов
/ 23 октября 2018

Ключевое слово 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(), метод doSth() в классе Animal выведет this, и это кошка.

0 голосов
/ 07 августа 2017

В C # вы можете вызвать метод любого предка, например:

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

Также вы можете сделать это в Delphi:

type
   A=class
      procedure foo;
      ...
   B=class(A)
     procedure foo; override;
     ...
   C=class(B)
     procedure foo; override;
     ...
A(objC).foo();

Но в Java вы можете сделать такой фокус только с помощью некоторого механизма. Один из возможных способов:

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

Результат вывода objC.DoIt ():

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
0 голосов
/ 17 апреля 2015
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();
    }
}

Вывод: напечатано в GrandDad

0 голосов
/ 16 февраля 2015

Это просто сделать. Например:

C подкласс B и B подкласс A. Например, оба из трех имеют метод methodName ().

публичный абстрактный класс A {

public void methodName() {
    System.out.println("Class A");
}

}

публичный класс B расширяет A {

public void methodName() {
    super.methodName();
    System.out.println("Class B");
}

// Will call the super methodName
public void hackSuper() {
    super.methodName();
}

}

открытый класс C расширяет 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");
}

}

Выполнить класс C Вывод будет: Класс А Класс С

Вместо вывода: Класс А Класс б Класс С

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...