Come forzare la classe derivata a chiamare il super metodo? (Come fa Android)


85

Mi chiedevo, quando la creazione di nuove Activityclassi e quindi l'override del onCreate()metodo, in eclisse ottengo sempre automaticamente aggiunto: super.onCreate(). Come avviene questo? C'è una parola chiave java nella classe abstract o genitore che lo impone?

Non so se sia illegale non chiamare la super classe, ma ricordo che in alcuni metodi ho ricevuto un'eccezione per non averlo fatto. Anche questo è integrato in java? Puoi usare qualche parola chiave per farlo? O come si fa?


Voglio sapere anche questo. E non è solo Eclipse ad essere utile, se rimuovo la chiamata a super.onCreate (), l'app restituisce un errore di runtime dicendo: "non ha chiamato super.onCreate ()". Quindi sì, ti costringe davvero a chiamare il super metodo. Ma come?
Rodrigo Castro,

@RodrigoCastro È possibile rivedere i javadoc per ogni metodo. Ad esempio onCreate () .

Risposte:


10

Ecco la fonte di Activity#onCreate()- sono quasi tutti i commenti ( originale - vedi riga ~ 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;
}

quindi, la mia ipotesi sarebbe che il plug-in ADT Eclipse sia ciò che aggiunge automaticamente quella chiamata super.onCreate()per te. È un'ipotesi totale, però.


2
Immagino che mCalled = truevenga utilizzato anche per una possibile eccezione. Forse non in, onCreate()ma quando effettivamente viene lanciata un'eccezione del genere, utilizzerà quel semplice schema.
Peterdk

194

Questo viene aggiunto nella libreria delle annotazioni di supporto:

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

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

@CallSuper


Sì, hai colpito nel segno qui. Grazie.
SMBiggs

Non ancora provato ma leggi la documentazione. Sarà fantastico, immagino. Questa dovrebbe essere la risposta accettata.
Rizwan Sohaib

1
Tutte le altre risposte sono totalmente schifose, tranne questa. Dovrebbe essere accettato.
Le_Enot

3
@ RizwanSohaib non ti costringerà a fare nulla. Si evidenzierà e ti farà sapere che devi chiamarlo. Per fare qualcosa di più complesso, avrai bisogno di un processore di annotazioni o di implementare la logica da solo. a seconda dell'IDE, dovrebbe impedire anche la compilazione.
gelido

1
Risposta perfetta. Grazie mille
Võ Quang Hòa

82

Se vuoi forzare le sottoclassi ad eseguire la logica della classe genitore, un modello comune è qualcosa come il seguente:

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

Questo in realtà non risponde alla tua domanda su cosa induce Eclipse a inserire automaticamente una chiamata di superclasse nell'implementazione; ma poi non penso che sia la strada da percorrere comunque in quanto questo può sempre essere cancellato.

Non si può effettivamente imporre che un metodo debba chiamare la versione della superclasse con una parola chiave Java o qualcosa del genere. Sospetto che le tue eccezioni provenissero semplicemente da un codice nella classe genitore che controlla gli invarianti previsti, o qualcosa del genere, che sono stati invalidati dal tuo approccio. Nota che questo è leggermente diverso dal lanciare un'eccezione perché non sei riuscito a chiamare super.onCreate().


8

Se vuoi essere assolutamente sicuro che venga chiamato anche il metodo della superclasse, devi truccare un po ': non permettere che il metodo della superclasse venga sovrascritto, ma chiamalo un metodo protetto sovrascrivibile.

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

In questo modo, l'utente deve chiamare Super.foo () o Base.foo () e sarà sempre la versione della classe base così come è stata dichiarata finale. La parte specifica dell'implementazione è in impl_stuff (), che può essere sovrascritta.


8

Per rispondere alla tua domanda attuale, la creazione automatica della chiamata a super.onCreate () è una funzionalità del plugin ADT. In java, non è possibile forzare direttamente una sottoclasse a chiamare la super implementazione di un metodo, afaik (vedere il modello descritto in altre risposte per aggirare il problema). Tuttavia, tieni presente che in Android non stai creando un'istanza di oggetti Activity (o oggetti Service) direttamente: passi un Intent al sistema e il sistema crea un'istanza dell'oggetto e chiama onCreate () su di esso (insieme ad altri metodi del ciclo di vita). Quindi il sistema ha un riferimento diretto all'oggetto dell'istanza Activity ed è in grado di controllare (presumibilmente) alcuni booleani impostati su true nell'implementazione della superclasse di onCreate (). Anche se non so esattamente come sia implementato, probabilmente assomiglia a questo:

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

E nella classe di livello "sistema" che riceve l'Intent e da esso istanzia l'oggetto Activity:

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

La mia ipotesi è che probabilmente sia leggermente più complesso di così, ma hai capito. Eclipse crea automaticamente la chiamata perché il plug-in ADT glielo dice, per comodità. Buona programmazione!


4

Non c'è nulla in Java che costringa a chiamare super, e ci sono molti esempi in cui non vorresti. L'unico posto in cui puoi forzare la chiamata di super è nei costruttori. Tutti i costruttori devono chiamare un costruttore di superclassi. Uno (il costruttore senza argomenti) verrà inserito se non ne scrivi uno esplicitamente, e se non c'è un costruttore senza argomenti, devi chiamarlo esplicitamente.


3

Eclipse ti sta solo aiutando, ricordandoti che puoi chiamare l'implementazione della superclasse se lo desideri.

probabilmente stai ricevendo un errore perché non stai facendo qualcosa di necessario che fa la superclasse, dato che non stai chiamando la sua implementazione.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.