Wie kann man eine abgeleitete Klasse zwingen, eine Supermethode aufzurufen? (Wie Android)

84

Ich habe mich gefragt, ob ich beim Erstellen neuer ActivityKlassen und beim Überschreiben der onCreate()Methode in Eclipse immer automatisch hinzugefügt werde : super.onCreate(). Wie kommt es dazu? Gibt es ein Java-Schlüsselwort in der abstrakten oder übergeordneten Klasse, das dies erzwingt?

Ich weiß nicht, ob es illegal ist, die Superklasse nicht aufzurufen, aber ich erinnere mich bei einigen Methoden, dass ich eine Ausnahme ausgelöst habe, weil ich dies nicht getan habe. Ist das auch in Java eingebaut? Können Sie dazu ein Schlüsselwort verwenden? Oder wie geht das?

Peterdk
quelle
Das möchte ich auch wissen. Und es ist nicht nur hilfreich, dass Eclipse hilfreich ist. Wenn ich den Aufruf von super.onCreate () entferne, gibt die App einen Laufzeitfehler aus, der besagt: "hat super.onCreate () nicht aufgerufen". Also ja, es zwingt dich wirklich, die Supermethode aufzurufen. Aber wie?
Rodrigo Castro
@RodrigoCastro Sie können die Javadocs für jede Methode überprüfen. Zum Beispiel onCreate () .

Antworten:

10

Hier ist die Quelle von Activity#onCreate()- es sind fast alle Kommentare ( Original - siehe Zeile ~ 800 ):

/**
 * Called when the activity is starting.  This is where most initialization
 * should go: calling {@link #setContentView(int)} to inflate the
 * activity's UI, using {@link #findViewById} to programmatically interact
 * with widgets in the UI, calling
 * {@link #managedQuery(android.net.Uri , String[], String, String[], String)} to retrieve
 * cursors for data being displayed, etc.
 *
 * <p>You can call {@link #finish} from within this function, in
 * which case onDestroy() will be immediately called without any of the rest
 * of the activity lifecycle ({@link #onStart}, {@link #onResume},
 * {@link #onPause}, etc) executing.
 *
 * <p><em>Derived classes must call through to the super class's
 * implementation of this method.  If they do not, an exception will be
 * thrown.</em></p>
 *
 * @param savedInstanceState If the activity is being re-initialized after
 *     previously being shut down then this Bundle contains the data it most
 *     recently supplied in {@link #onSaveInstanceState}.  <b><i>Note: Otherwise it is null.</i></b>
 *
 * @see #onStart
 * @see #onSaveInstanceState
 * @see #onRestoreInstanceState
 * @see #onPostCreate
 */
protected void onCreate(Bundle savedInstanceState) {
    mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
            com.android.internal.R.styleable.Window_windowNoDisplay, false);
    mCalled = true;
}

Ich würde also vermuten, dass das ADT Eclipse-Plugin das ist, was diesen Aufruf automatisch super.onCreate()für Sie hinzufügt . Es ist jedoch eine totale Vermutung.

Matt Ball
quelle
2
Ich denke das mCalled = truewird auch für eine mögliche Ausnahme verwendet. Vielleicht nicht in der, onCreate()aber wenn tatsächlich eine solche Ausnahme ausgelöst wird, wird dieses einfache Muster verwendet.
Peterdk
190

Dies wird in der Support-Anmerkungsbibliothek hinzugefügt:

dependencies {
    compile 'com.android.support:support-annotations:22.2.0'
}

http://tools.android.com/tech-docs/support-annotations

@ CallSuper

runor49
quelle
Ja, du hast hier den Nagel auf den Kopf getroffen. Vielen Dank.
SMBiggs
Noch nicht ausprobiert, aber lesen Sie die Dokumentation. Das wird großartig, denke ich. Dies sollte die akzeptierte Antwort sein.
Rizwan Sohaib
1
Alle anderen Antworten sind total beschissen, außer dies. Sollte akzeptiert werden.
Le_Enot
3
@ RizwanSohaib es wird dich nicht zwingen, etwas zu tun. Es wird hervorgehoben und Sie wissen lassen, dass Sie es anrufen müssen. Um etwas komplexeres zu tun, benötigen Sie entweder einen Anmerkungsprozessor oder müssen die Logik selbst implementieren. Abhängig von der IDE sollte dies auch das Bauen verhindern.
frostymarvelous
1
Perfekte Antwort. Vielen Dank
Võ Quang Hòa
81

Wenn Sie Unterklassen zwingen möchten , die Logik der übergeordneten Klasse auszuführen, sieht ein allgemeines Muster wie folgt aus:

public abstract class SuperClass implements SomeInterface
{
    // This is the implementation of the interface method
    // Note it's final so it can't be overridden
    public final Object onCreate()
    {
        // Hence any logic right here always gets run
        // INSERT LOGIC

        return doOnCreate();

        // If you wanted you could instead create a reference to the
        // object returned from the subclass, and then do some
        // post-processing logic here
    }

    protected abstract Object doOnCreate();
}

public class Concrete extends SuperClass
{
    @Override
    protected Object doOnCreate()
    {
        // Here's where the concrete class gets to actually do
        // its onCreate() logic, but it can't stop the parent
        // class' bit from running first

        return "Hi";
    }
}

Dies beantwortet nicht wirklich Ihre Frage, was Eclipse dazu veranlasst, automatisch einen Aufruf der Oberklasse in die Implementierung einzufügen. aber dann denke ich nicht, dass das sowieso der richtige Weg ist, da dies immer gelöscht werden kann.

Sie können nicht wirklich erzwingen, dass eine Methode die Version der Oberklasse mit einem Java-Schlüsselwort oder ähnlichem aufrufen muss. Ich vermute, dass Ihre Ausnahmen einfach von einem Code in der übergeordneten Klasse herrühren, der erwartete Invarianten überprüft, oder etwas, das durch Ihren Ansatz ungültig gemacht wurde. Beachten Sie, dass sich dies geringfügig vom Auslösen einer Ausnahme unterscheidet, da Sie nicht aufgerufen haben super.onCreate().

Andrzej Doyle
quelle
8

Wenn Sie unbedingt sicherstellen möchten, dass auch die Superklassenmethode aufgerufen wird, müssen Sie einen kleinen Trick ausführen: Lassen Sie nicht zu, dass die Superklassenmethode überschrieben wird, sondern lassen Sie sie eine überschreibbare geschützte Methode aufrufen.

class Super
{
   public final void foo() {
      foo_stuff();
      impl_stuff();
   }

   protected void impl_stuff() {
      some_stuff_that_you_can_override();
   }
}

class Base extends Super
{
  protected void impl_stuff() { 
     my_own_idea_of_impl();
  }
}

Auf diese Weise muss der Benutzer Super.foo () oder Base.foo () aufrufen und es wird immer die Basisklassenversion sein, wie sie als endgültig deklariert wurde. Das implementierungsspezifische Material befindet sich in impl_stuff (), das überschrieben werden kann.

Lagerbaer
quelle
8

Um Ihre eigentliche Frage zu beantworten, ist die automatische Erstellung des Aufrufs von super.onCreate () eine Funktion des ADT-Plugins. In Java können Sie eine Unterklasse nicht direkt zwingen, die Superimplementierung einer Methode afaik aufzurufen (siehe das in anderen Antworten beschriebene Muster zur Umgehung). Beachten Sie jedoch, dass Sie in Android Aktivitätsobjekte (oder Serviceobjekte) nicht direkt instanziieren - Sie übergeben eine Absicht an das System und das System instanziiert das Objekt und ruft onCreate () auf (zusammen mit anderen Lebenszyklusmethoden). Das System hat also einen direkten Objektverweis auf die Activity-Instanz und kann (vermutlich) einen Booleschen Wert überprüfen, der in der Superklassen-Implementierung von onCreate () auf true gesetzt ist. Obwohl ich nicht genau weiß, wie es implementiert ist, sieht es wahrscheinlich ungefähr so ​​aus:

class Activity
{
  onCreate()
  {
    superCalled = true;
    ...
  }
  ...
}

Und in der Level-Klasse "System", die die Absicht empfängt und das Activity-Objekt daraus instanziiert:

...
SomeActivitySubclass someActivitySubclassObject = new SomeActivitySubclass();
someActivitySubclassObject.onCreate();
if (!someActivityObject.isSuperCalled())
{
  Exception e = new Exception(...) //create an exception with appropriate details
  throw e;
}

Ich vermute, es ist wahrscheinlich etwas komplexer, aber Sie haben die Idee. Eclipse erstellt den Anruf automatisch, da das ADT-Plugin ihn aus praktischen Gründen dazu auffordert. Viel Spaß beim Codieren!

Sprechcode
quelle
4

In Java gibt es nichts, was das Aufrufen von Super erzwingt, und es gibt viele Beispiele, bei denen Sie dies nicht möchten. Der einzige Ort, an dem Sie das Aufrufen von Super erzwingen können, sind Konstruktoren. Alle Konstruktoren müssen einen Konstruktor der Oberklasse aufrufen. Einer (der Konstruktor ohne Argumente) wird eingefügt, wenn Sie keinen explizit schreiben, und wenn es keinen Konstruktor ohne Argumente gibt, müssen Sie ihn explizit aufrufen.

DJClayworth
quelle
3

Eclipse ist nur hilfreich und erinnert Sie daran, dass Sie die Implementierung der Superklasse aufrufen können, wenn Sie möchten.

Sie erhalten wahrscheinlich eine Fehlermeldung, weil Sie nicht das tun, was die Oberklasse benötigt, da Sie ihre Implementierung nicht aufrufen.

hvgotcodes
quelle