426 Stimmen

Warum ist super.super.method(); in Java nicht erlaubt?

Ich lese diese Frage und dachte, das wäre leicht zu lösen (nicht, dass es nicht auch ohne zu lösen wäre), wenn man schreiben könnte:

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

Ich bin mir nicht sicher, ob dies in vielen Fällen nützlich ist, aber ich frage mich なぜ es nicht ist und ob es so etwas in anderen Sprachen gibt.

Was haltet ihr davon?

EDITAR: Um das klarzustellen: Ja, ich weiß, das ist in Java unmöglich und ich vermisse es nicht wirklich. Ich habe nicht erwartet, dass das funktioniert und war überrascht, dass ich einen Compilerfehler bekomme. Ich hatte nur die Idee und möchte sie gerne diskutieren.

3voto

ruruskyi Punkte 1931

Der Aufruf von super.super.method() ist sinnvoll, wenn Sie den Code der Basisklasse nicht ändern können. Dies ist häufig der Fall, wenn Sie eine bestehende Bibliothek erweitern.

Fragen Sie sich zunächst, warum Sie diese Klasse erweitern? Wenn die Antwort lautet: "Weil ich sie nicht ändern kann", dann können Sie ein genaues Paket und eine genaue Klasse in Ihrer Anwendung erstellen und die unanständige Methode umschreiben oder einen Delegaten erstellen:

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

Sie können zum Beispiel Folgendes erstellen org.springframework.test.context.junit4.SpringJUnit4ClassRunner Klasse in Ihrer Anwendung, so dass diese Klasse vor der eigentlichen Klasse aus jar geladen werden sollte. Schreiben Sie dann Methoden oder Konstruktoren um.

Achtung! Dies ist ein absoluter Hack, dessen Verwendung NICHT empfohlen wird, aber er funktioniert! Die Verwendung dieses Ansatzes ist wegen möglicher Probleme mit Klassenladern gefährlich. Außerdem kann dies jedes Mal Probleme verursachen, wenn Sie eine Bibliothek aktualisieren, die eine überschriebene Klasse enthält.

2voto

xMichal Punkte 574

Ich würde den Körper der super.super-Methode in eine andere Methode packen, wenn möglich

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

Wenn Sie die Super-Super-Klasse nicht ändern können, können Sie auch dies versuchen:

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

In beiden Fällen ist die

new ChildClass().toString();

Ergebnisse zu "Ich bin super super"

1voto

Boris Punkte 19
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);

     }
}

laufen: A BUILD SUCCESSFUL (Gesamtzeit: 0 Sekunden)

1voto

Ganesh Iyer Punkte 11

Ich habe Situationen wie diese, wenn die Architektur ist es, gemeinsame Funktionalität in einer gemeinsamen CustomBaseClass, die im Namen von mehreren abgeleiteten Klassen implementiert bauen hatte. Wir müssen jedoch die gemeinsame Logik für eine bestimmte Methode für eine bestimmte abgeleitete Klasse umgehen. In solchen Fällen müssen wir eine super.super.methodX-Implementierung verwenden.

Dies wird durch die Einführung eines booleschen Elements in der CustomBaseClass erreicht, das dazu verwendet werden kann, die benutzerdefinierte Implementierung selektiv aufzuschieben und auf die Standard-Rahmenimplementierung zurückzugreifen, wo dies wünschenswert ist.

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

Mit guten Architekturprinzipien, die sowohl im Framework als auch in der Anwendung befolgt werden, könnten wir solche Situationen jedoch leicht vermeiden, indem wir den hasA-Ansatz anstelle des isA-Ansatzes verwenden. Aber zu allen Zeiten ist es nicht sehr praktisch zu erwarten, gut gestaltete Architektur in Ort, und damit die Notwendigkeit, weg von soliden Design-Prinzipien und Hacks wie diese einzuführen. Nur meine 2 Cents...

1voto

Dexygen Punkte 12014

Es scheint möglich zu sein, zumindest die Klasse der Superklasse der Superklasse, wenn auch nicht notwendigerweise die Instanz davon, mit Hilfe von Reflexion zu erhalten; wenn dies nützlich sein könnte, beachten Sie bitte die Javadoc unter [http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getSuperclass()](http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getSuperclass())

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X