Wann sollte die super () -Methode beim Überschreiben NICHT aufgerufen werden?

113

Wenn ich meine eigene benutzerdefinierte Android-Klasse erstelle, ist dies extenddie native Klasse. Dann , wenn ich die Basismethode außer Kraft setzen wollen, habe ich immer anrufen super()Methode, so wie ich es immer tue in onCreate, onStopusw.

Und ich dachte, das ist es, da das Android-Team uns von Anfang an geraten hat, immer superjede Methodenüberschreibung aufzurufen .

Aber in vielen Büchern kann ich sehen, dass Entwickler, die erfahrener sind als ich, das Anrufen oft unterlassen, superund ich bezweifle wirklich, dass sie dies aus Mangel an Wissen tun. Schauen Sie sich zum Beispiel diese grundlegende SAX- Parser-Klasse an, superin der weggelassen wird startElement, charactersund endElement:

public class SAXParser extends DefaultHandler{
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        if(qName.equalsIgnoreCase("XXY")) {
            //do something
        }
    }

    public void characters(char[] ch, int start, int length) throws SAXException {
        //do something
    }

    public void endElement(String uri, String localName, String qName) throws SAXException {
        if(qName.equalsIgnoreCase("XXY")) {
            //do something
        }else () {
            //do something
        }
    }
}

Wenn Sie versuchen, eine Überschreibungsmethode über Eclipse oder eine andere IDE zu erstellen, superwird diese immer als Teil eines automatisierten Prozesses erstellt.

Dies war nur ein einfaches Beispiel. Bücher sind voll von ähnlichem Code .

Woher wissen sie, wann Sie anrufen müssen superund wann Sie das Anrufen unterlassen können?

PS. Binden Sie nicht an dieses spezielle Beispiel. Es war nur ein Beispiel, das zufällig aus vielen Beispielen ausgewählt wurde.

(Das klingt vielleicht nach einer Anfängerfrage, aber ich bin wirklich verwirrt.)

Sandale
quelle
3
endElementDas API-Dokument lautet "Standardmäßig nichts tun. Anwendungsschreiber können diese Methode überschreiben ...", was bedeutet, dass Sie Super sicher aufrufen können, weil es "nichts" tut, aber Sie müssen es nicht und Sie können es wirklich überschreiben. Sie können oft feststellen, ob Sie dies tun müssen / können / sollten, wenn Sie das Dokument für diese Methode lesen.
Zapl
1
Kleines Beispiel: Ich verwende onBackPressed () im Begrüßungsbildschirm und rufe NICHT super an, damit der Spritzer nicht ausgeht, sondern nur die Schaltfläche deaktiviert wird.
Bojan Kogoj
@sandalone Tut mir leid, dass Sie hier gefragt haben, aber haben Sie Erfahrung mit dem Umgang mit Mehrwertsteuer bei In-App-Abrechnungen und in welchen Ländern wird dies automatisch von Google durchgeführt und an welche muss ich die Mehrwertsteuer manuell melden / zahlen? siehe stackoverflow.com/questions/36506835/…
Vidar Vestnes

Antworten:

144

Durch das Aufrufen der superMethode überschreiben Sie nicht das Verhalten der Methode, sondern erweitern es.

Ein Aufruf von superführt jede Logik aus, die die Klasse, die Sie erweitern, für diese Methode definiert hat. Berücksichtigen Sie, dass es in dem Moment wichtig sein kann, in dem Sie die superImplementierung in Ihrer Methode überschreiben. Zum Beispiel:

public class A { 
    public void save() { 
         // Perform save logic
    }
}

public class B extends A {
    private Object b;
    @Override
    public void save() { 
        super.save(); // Performs the save logic for A
        save(b); // Perform additional save logic
    }
}

Ein Aufruf von B.save()führt die save()Logik für beide Aund Bin dieser bestimmten Reihenfolge aus. Wenn Sie nicht super.save()drinnen anrufen würden B.save(), A.save()würden Sie nicht angerufen werden. Und wenn Sie rief super.save()nach save(b), A.save()würde effektiv danach durchgeführt werden B.save().

Wenn Sie das Verhalten überschreiben möchten super(dh die Implementierung vollständig ignorieren und alles selbst bereitstellen möchten ), sollten Sie nicht anrufen super.

Im SAXParserBeispiel , das Sie zur Verfügung stellen, die Implementierungen von DefaultHandlersind für diese Methoden nur leer, so dass Subklassen sie außer Kraft setzen kann und ein Verhalten für diese Methoden zur Verfügung stellen. Im Javadoc für diese Methode wird auch darauf hingewiesen.

public void startElement (String uri, String localName,
    String qName, Attributes attributes) throws SAXException {
    // no op
}

Über den super()von IDEs generierten Standardaufruf in Code, wie @barsjuin seinem Kommentar ausgeführt, gibt es in jedem Konstruktor einen impliziten Aufruf von super()(auch wenn Sie ihn nicht in Ihren Code schreiben), was in diesem Zusammenhang einen Aufruf von super'bedeutet. s Standardkonstruktor. Das IDEschreibt es nur für Sie auf, aber es würde auch aufgerufen, wenn Sie es entfernen. Beachten Sie auch, dass bei der Implementierung von Konstruktoren super()oder einer ihrer Varianten mit Argumenten (dh super(x,y,z)) nur ganz am Anfang der Methode aufgerufen werden kann .

Xavi López
quelle
14
Beachten Sie auch nicht, dass für Konstruktoren super()(der Standardkonstruktor der Superklasse) immer aufgerufen wird, auch wenn Sie ihn nicht angeben. Wenn die Superklasse keinen Standardkonstruktor hat, wird ein Kompilierungsfehler angezeigt, wenn Sie einen der Konstruktoren der Superklasse nicht explizit als Ihre erste Anweisung im Unterklassenkonstruktor aufrufen.
Barsju
1
Ja, es ist im Grunde nur Faulheit - für Methoden, von denen wir wissen, dass sie nichts tun, lassen Sie es der Kürze halber einfach weg
Voo
1
Vielen Dank für Ihre wertvollen Kommentare, @barjsu, ich habe diese Details in die Antwort aufgenommen.
Xavi López
16

Woher wissen sie, wann Sie super anrufen müssen und wann Sie es weglassen können?

Wenn eine spezielle API-Methode eine kritische Bedeutung für den zugrunde liegenden Framework-Kontext-Lebenszyklus hat, wird sie normalerweise wie die Activity.onCreate()API-Dokumentation in der API-Dokumentation immer explizit angegeben und hervorgehoben . Wenn die API einem robusten Design folgt, sollte sie außerdem einige Ausnahmen auslösen, um den Consumer-Entwickler zur Kompilierungszeit des Projekts zu warnen und sicherzustellen, dass zur Laufzeit kein Fehler generiert wird.

Wenn dies in der API-Dokumentation nicht explizit angegeben ist, kann der Consumer-Entwickler davon ausgehen, dass die API-Methode beim Überschreiben nicht unbedingt aufgerufen werden muss. Es ist Sache des Consumer-Entwicklers, zu entscheiden, ob das Standardverhalten verwendet ( superMethode aufrufen ) oder vollständig überschrieben werden soll.

Wenn die Bedingung zulässig ist (ich liebe Open-Source-Software), kann der Consumer-Entwickler jederzeit den API-Quellcode überprüfen und sehen, wie die Methode tatsächlich unter die Haube geschrieben wird. Schauen Sie sich zum Beispiel Activity.onCreate()Quelle und DefaultHandler.startElement()Quelle an.

yorkw
quelle
Vielen Dank, dass Sie mir zusätzliche Dinge erklärt haben. Vielen Dank, dass Sie mich daran erinnert haben, den Quellcode zu überprüfen.
Sandalone
7

Der Test, den Sie in Ihrem Kopf machen sollten, ist:

"Möchte ich die gesamte Funktionalität dieser Methode für mich erledigen und danach etwas tun?" Wenn ja, möchten Sie aufrufen super()und dann Ihre Methode beenden. Dies gilt für "wichtige" Methoden wie onDraw(), die viele Dinge im Hintergrund behandeln.

Wenn Sie nur einen Teil der Funktionalität wünschen (wie bei den meisten Methoden, die Sie überschreiben werden), möchten Sie wahrscheinlich nicht aufrufen super().

Michael
quelle
3

Nun, Xavi hat eine bessere Antwort gegeben. Aber Sie wissen wahrscheinlich, was zu super()tun ist, wenn Sie eine überschriebene Methode aufrufen. Es zeigt an, was Sie mit dem Standardverhalten gemacht haben.

z.B:

onDraw() 

Methode in der View-Klasse, wenn sie überschrieben wird. Sie zeichnen etwas, bevor Sie super.onDraw () sagen. Es wird angezeigt, sobald die Ansicht vollständig gezeichnet ist. Hier ist ein Aufruf supererforderlich, da Android einige wichtige Dinge zu tun hat (wie onCreate ()).

aber zur selben Zeit

onLongClick()

Wenn Sie dies überschreiben, möchten Sie nicht super aufrufen, da ein Dialogfeld mit einer Liste von Optionen für einen EditText oder eine andere ähnliche Ansicht angezeigt wird. Dies ist der grundlegende Unterschied. Sie haben die Wahl, ihn einige Male zu belassen. Aber für andere Methoden wie onCreate() , onStop()Sie sollten das Betriebssystem damit umgehen lassen ..

ngesh
quelle
2

Ich habe Ihre Frage nicht klar verstanden, aber wenn Sie sich fragen, warum Sie die superMethode nicht aufrufen :

Es gibt einen Grund für den Aufruf der superMethode: Wenn es in der übergeordneten Klasse keinen Null-Argument-Konstruktor gibt, ist es nicht möglich, eine untergeordnete Klasse dafür zu erstellen. Entweder müssen Sie einen Konstruktor ohne Argumente in der übergeordneten Klasse behalten, oder Sie benötigen zu definieren super()Aufruf - Anweisung mit argument(how much argument constructor you have used in super class)an der Spitze des Kindes Klassenkonstruktors.

Ich hoffe das hilft. Wenn nicht, lass es mich wissen.

Vikas Gupta
quelle
2

Ich habe eine Constraint-Array-Liste wie implementiert

public class ConstraintArrayList<T> extends ArrayList<T> {
  ConstraintArrayList(Constraint<T> cons) {this.cons = cons;}
  @Override
  public boolean add(T element) {
    if (cons.accept(element))
      return super.add(element);
    return false;
  }
}

Wenn Sie sich den Code ansehen, wird lediglich eine Vorprüfung durchgeführt, bevor die Superklasse das eigentliche Hinzufügen eines Elements zur Liste durchführt. Dies ist einer der beiden Gründe für das Überschreiben von Methoden:

  1. Erweiterbarkeit, wo Sie erweitern möchten, was die Superklasse kann
  2. Spezifität, bei der Sie durch Polymorphismus ein bestimmtes Verhalten hinzufügen möchten, wie im Beispiel der Bewegungssemantik im allgemeinen Tierreich, in der sich die Art und Weise, wie sich Vögel bewegen (fliegen) und Frösche bewegen (hüpfen), für jede Unterklasse spezifisch ist.
Maress
quelle
2

Für diejenigen, die sich auch gefragt haben, welche überschriebenen Methoden von Android Framework superdiese Frage aufrufen und finden sollen - hier ist ein aktueller Hinweis aus dem Jahr 2019 -, wird Android Studio 3+ Ihnen sagen, wann Sie sie benötigen .

Geben Sie hier die Bildbeschreibung ein

dominik
quelle