Dlaczego jest super.super.method (); niedozwolone w Javie?

Przeczytałem to pytanie i pomyślałem, że łatwo będzie to rozwiązać (nie, że nie da się go rozwiązać bez), Jeśli można napisać:

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

Nie jestem pewien, czy jest to przydatne w wielu przypadkach, ale zastanawiam się Dlaczego nie jest i czy coś takiego istnieje w innych językach.

Co myślicie?

EDIT: Dla wyjaśnienia: tak Wiem, to niemożliwe w Javie i tak naprawdę za tym nie tęsknię. To nic, czego oczekiwałem do pracy i byłem zaskoczony otrzymaniem błąd kompilatora. Po prostu wpadłem na pomysł i chciałbym o tym porozmawiać.

Author: Community, 2009-02-25

21 answers

To narusza hermetyzację. Nie powinieneś być w stanie ominąć zachowania rodziców. To ma sens, aby czasami być w stanie ominąć zachowanie Twojej własnej klasy (szczególnie z tej samej metody), ale nie Twojego rodzica. na przykład, załóżmy, że mamy bazową "kolekcję elementów", podklasę reprezentującą "zbiór czerwonych elementów" i podklasę reprezentującą "zbiór dużych czerwonych elementów". Ma sens mieć:

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

To dobrze-RedItems może zawsze upewnij się, że elementy, które zawiera, Są czerwone. Załóżmy, że jesteśmy w stanie zadzwonić do super.super.add ():

public class NaughtyItems extends RedItems
{
    @Override
    public void add(Item item)
    {
        // I don't care if it's red or not. Take that, RedItems!
        super.super.add(item);
    }
}

Teraz możemy dodać co chcemy, i niezmiennik w {[2] } jest uszkodzony.

Czy to ma sens?
 437
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-31 14:45:02

Myślę, że Jon Skeet ma poprawną odpowiedź. Chciałbym tylko dodać, że możesz uzyskać dostęp do shadowed variables z superklas superklases, odlewając 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();
        }
}

Który wytwarza wyjście:

x=              3
super.x=        2
((T2)this).x=   2
((T1)this).x=   1
((I)this).x=    0

(Przykład z JLS )

Nie działa to jednak w przypadku wywołań metod, ponieważ wywołania metod są określane na podstawie typu runtime obiektu.

 61
Author: Michael Myers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-26 19:49:54

Myślę, że poniższy kod pozwala na użycie super.super...super.method() w większości przypadków. (nawet jeśli to brzydkie)

W skrócie

  1. Tworzenie tymczasowej instancji typu ancestor
  2. kopiowanie wartości pól z oryginalnego obiektu do tymczasowego
  3. wywołanie metody docelowej na obiekcie tymczasowym
  4. skopiuj zmodyfikowane wartości z powrotem do oryginalnego obiektu

Użycie:

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);
    }
}
 37
Author: Nico,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-01 23:17:58

Nie mam wystarczającej reputacji, aby skomentować, więc dodam to do innych odpowiedzi.

Jon Skeet odpowiada doskonale, z pięknym przykładem. Matt B ma rację: nie wszystkie superklasy mają supers. Twój kod złamie się, jeśli zadzwonisz do super super, który nie ma super.

Programowanie obiektowe (czym jest Java) polega na obiektach, a nie funkcjach. Jeśli chcesz programowania zorientowanego na zadania, wybierz C++ lub coś innego. Jeśli twój obiekt nie mieści się w super klasie, następnie musisz dodać go do "klasy dziadków", utworzyć nową klasę lub znaleźć inną super, do której pasuje.

Osobiście uważam to ograniczenie za jedną z największych zalet Javy. Kod jest nieco sztywny w porównaniu do innych języków, których używałem, ale zawsze wiem, czego się spodziewać. Pomaga to w "prostym i znanym" celu Javy. W mojej głowie, dzwoni super.super nie jest proste lub znajome. Być może deweloperzy czuli to samo?

 10
Author: EllaJo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-07 14:28:39

Jest kilka dobrych powodów, aby to zrobić. Możesz mieć podklasę, która ma metodę, która jest zaimplementowana nieprawidłowo, ale metoda nadrzędna jest zaimplementowana poprawnie. Ponieważ należy do biblioteki innej firmy, możesz nie być w stanie / nie chcesz zmienić źródła. W tym przypadku, chcesz utworzyć podklasę, ale nadpisać jedną metodę, aby wywołać super.super metoda.

Jak pokazują inne plakaty, można to zrobić poprzez refleksję, ale powinno być możliwe coś jak

(SuperSuperClass this).theMethod ();

Mam teraz do czynienia z tym problemem-szybką poprawką jest skopiowanie i wklejenie metody superclass do metody subsubclass:)

 8
Author: Larry Watanabe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-07 14:24:56

Poza bardzo dobrymi uwagami, które poczynili inni, myślę, że jest inny powód: co jeśli superklasa nie ma superklasy?

Ponieważ każda klasa naturalnie rozszerza (przynajmniej) Object, super.whatever() zawsze będzie odnosić się do metody w klasie nadrzędnej. Ale co, jeśli twoja klasa tylko rozszerza Object - do czego by się wtedy odnosiło super.super? Jak powinno być obsługiwane takie zachowanie-błąd kompilatora, NullPointer, itp?

Myślę, że głównym powodem, dla którego nie jest to dozwolone, jest to, że narusza enkapsulację, ale to też może być mały powód.

 7
Author: matt b,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-25 15:34:04

Myślę, że jeśli nadpisujesz metodę i chcesz mieć jej całą super-klasową wersję (np. equals), to praktycznie zawsze chcesz najpierw wywołać bezpośrednią superklasową wersję, która z kolei wywoła jej superklasową wersję, jeśli chce.

Myślę, że to rzadko ma sens (jeśli w ogóle. nie przychodzi mi do głowy przypadek, w którym to robi), aby wywołać jakąś arbitralną superklasową wersję metody. Nie wiem czy to w ogóle możliwe w Javie. Można to zrobić w C++:
this->ReallyTheBase::foo();
 3
Author: Johannes Schaub - litb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-25 15:14:41

Na zgadywanie, bo nie jest używany tak często. Jedynym powodem, dla którego mogłem go używać, jest to, że twój bezpośredni rodzic zmienił niektóre funkcje i próbujesz przywrócić je z powrotem do oryginału.

Co wydaje mi się sprzeczne z zasadami OO, ponieważ bezpośredni rodzic klasy powinien być bliżej spokrewniony z Twoją klasą niż z dziadkiem.

 2
Author: Powerlord,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-25 15:16:12

Ja bym postawił super.super ciało metody w innej metodzie, jeśli to możliwe

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

Lub jeśli nie możesz zmienić super-super klasy, Możesz spróbować tego:

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

W obu przypadkach,

new ChildClass().toString();

Wyniki do "jestem super super"

 2
Author: xMichal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-29 12:32:46

Wydaje się, że możliwe jest przynajmniej uzyskanie klasy superclass ' s superclass, choć niekoniecznie jej instancji, używając reflection; jeśli to może być przydatne, proszę rozważyć Javadoc w http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getSuperclass()

 1
Author: George Jempty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-02 20:22:11
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);

     }
}

Run: A BUILD SUCCESSFUL (łączny czas: 0 sekund)

 1
Author: Boris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-20 19:59:49

Miałem takie sytuacje, kiedy architektura ma budować wspólną funkcjonalność we wspólnej CustomBaseClass, która implementuje w imieniu kilku klas pochodnych. Musimy jednak obejść wspólną logikę dla konkretnej metody dla określonej klasy pochodnej. W takich przypadkach musimy użyć super.super.implementacja metodyx.

Osiągamy to poprzez wprowadzenie elementu logicznego w CustomBaseClass, który może być użyty do selektywnego odkładania niestandardowej implementacji i poddania się implementacja domyślnego frameworka tam, gdzie jest to pożądane.

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

Jednak z zasadami dobrej architektury stosowanymi zarówno w frameworku, jak i w aplikacji, możemy łatwo uniknąć takich sytuacji, stosując podejście hasA, zamiast podejścia isA. Ale w każdym momencie nie jest zbyt praktycznym oczekiwać dobrze zaprojektowanej architektury na miejscu, a tym samym konieczność odejścia od solidnych zasad projektowania i wprowadzenia takich hacków. Tylko moje 2 centy...

 1
Author: Ganesh Iyer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-27 05:51:35

@ Jon Skeet ładne Wyjaśnienie. IMO jak ktoś chce zadzwonić super.super metoda wtedy trzeba być chcesz zignorować zachowanie najbliższego rodzica, ale chcesz uzyskać dostęp do zachowania Wielkiego rodzica. Można to osiągnąć poprzez przykład. Jak poniżej kod

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

Oto Klasa kierowcy,

public class Driver {
    public static void main(String[] args) {
        C c = new C();
        c.printClass();
    }
}

Wyjście tego będzie

In C Class
In A Class

Zachowanie klasy B printClass będzie w tym przypadku ignorowane. Nie jestem pewien, czy jest to idealna lub dobra praktyka, aby osiągnąć super.super, ale i tak to działa.

 1
Author: Sanjay Jain,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-04 06:18:10

Jeśli myślisz, że będziesz potrzebował superklasy, możesz odwołać się do niej w zmiennej dla tej klasy. Na przykład:

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

Powinien wydrukować:

2
1
0
 0
Author: Ashtheking,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-20 14:26:15

IMO, to czysty sposób na osiągnięcie super.super.sayYourName() zachowania w Javie.

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

Wyjście:

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

 0
Author: Yakov Fain,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-13 09:48:27

Powołanie super.super.metoda() ma sens, gdy nie można zmienić kodu klasy bazowej. Dzieje się tak często, gdy rozszerzasz istniejącą bibliotekę.

Najpierw zadaj sobie pytanie, dlaczego przedłużasz te zajęcia? Jeśli odpowiedź brzmi "ponieważ nie mogę tego zmienić", możesz utworzyć dokładny pakiet i klasę w swojej aplikacji i przepisać metodę naughty lub utworzyć delegata:

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() {...}
    ...
}

Na przykład, można utworzyć org.springframework.test.kontekst.junit4SpringJUnit4ClassRunner klasa w aplikacji więc klasa ta powinna być załadowana przed prawdziwą z jar. Następnie przepisać metody lub konstruktory.

Uwaga: jest to absolutny hack, i jest wysoce nie zaleca się używać, ale to działa! Stosowanie tego podejścia jest niebezpieczne ze względu na Możliwe problemy z ładowarkami klasowymi. Może to również powodować problemy za każdym razem, gdy zaktualizujesz bibliotekę zawierającą nadpisaną klasę.

 0
Author: ruruskyi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-16 15:00:10

Myślę, że jest to problem, który łamie umowę spadkową.
Rozszerzając klasę przestrzegasz / akceptujesz jej zachowanie, cechy
Podczas gdy dzwoniąc super.super.method(), chcesz złamać własną umowę posłuszeństwa.

po prostu nie można wybrać cherry z super klasy .

Jednak mogą się zdarzyć sytuacje, gdy poczujesz potrzebę wywołania super.super.method() - zazwyczaj zły znak projektu, w kodzie lub w kodzie, który dziedziczysz !
Jeśli super i super super klasy nie mogą być refakturowane (niektóre starsze kody), a następnie zdecydować się na kompozycję zamiast dziedziczenia.

Łamanie enkapsulacji następuje, gdy @Override niektóre metody przerywają kod enkapsulowany. Metody mające nie być nadpisywane są oznaczone finał .

 0
Author: DayaMoon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-09 08:13:39

W C# możesz wywołać metodę dowolnego przodka w następujący sposób:

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

Również możesz to zrobić w Delphi:

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

Ale w Javie można zrobić takie skupienie tylko przez jakiś sprzęt. Jednym z możliwych sposobów jest:

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 () wynik wyjściowy:

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
Author: D.Motyl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-07 19:56:51

Spójrz na ten Projekt Github, zwłaszcza zmienna objectHandle. Ten projekt pokazuje, jak właściwie i dokładnie nazwać metodę dziadka na wnuku.

Na wypadek, gdyby link się zepsuł, oto kod:

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";
        }
    }
}
Szczęśliwego Kodowania!!!!
 0
Author: kyay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-15 16:48:28

To jest po prostu łatwe do zrobienia. Na przykład:

C podklasa B i B podklasa A. Obie z trzech mają na przykład metodę methodName ().

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

}

Run class C Output będzie: Klasa A Klasa C

Zamiast wyjścia: Klasa A Klasa B Klasa C

 -1
Author: user2490562,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-16 12:08:56
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();
    }
}

Output: Printed in the Prad

 -1
Author: Andrey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-17 05:48:36