¿Cómo forzar a la clase derivada a llamar al súper método? (Como hace Android)


85

Me preguntaba, al crear nuevas Activityclases y luego reemplazando el onCreate()método, en Eclipse que siempre se añaden automático: super.onCreate(). ¿Como sucedió esto? ¿Hay una palabra clave java en la clase abstracta o principal que fuerce esto?

No sé si es ilegal no llamar a la superclase, pero recuerdo que en algunos métodos obtuve una excepción por no hacer esto. ¿Esto también está integrado en Java? ¿Puedes usar alguna palabra clave para hacer eso? ¿O como se hace?


Quiero saber esto también. Y no es solo que Eclipse sea útil, si elimino la llamada a super.onCreate (), la aplicación da un error de tiempo de ejecución que dice: "no llamó a super.onCreate ()". Entonces sí, realmente te está obligando a llamar al súper método. ¿Pero cómo?
Rodrigo Castro

@RodrigoCastro Puede revisar los javadocs para cada método. Por ejemplo, onCreate () .

Respuestas:


10

Aquí está la fuente de Activity#onCreate()- son casi todos los comentarios ( original - vea la línea ~ 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;
}

entonces, supongo que el complemento ADT Eclipse es lo que agrega automáticamente esa llamada super.onCreate()para usted. Sin embargo, es una suposición total.


2
Supongo que mCalled = truetambién se usa para una posible excepción. Quizás no en el, onCreate()pero cuando efectivamente se lanza una excepción de este tipo, usará ese patrón simple.
Peterdk

192

Esto se agrega en la biblioteca de anotaciones de soporte:

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

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

@CallSuper


Sí, has dado en el clavo aquí. Gracias.
SMBiggs

Aún no lo he probado, pero lea la documentación. Esto va a ser increíble, supongo. Esta debería ser la respuesta aceptada.
Rizwan Sohaib

1
Todas las otras respuestas son totalmente basura, excepto esta. Debería ser aceptado.
Le_Enot

3
@RizwanSohaib, no te obligará a hacer nada. Se resaltará y le hará saber que necesita llamarlo. Para hacer algo más complejo, necesitará un procesador de anotaciones o implementar la lógica usted mismo. Dependiendo del IDE, también debería impedirle construir.
frostymarvelous

1
Respuesta perfecta. Muchas gracias
Võ Quang Hòa

82

Si desea forzar a las subclases a ejecutar la lógica de la clase principal, un patrón común es algo como el siguiente:

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

En realidad, esto no responde a su pregunta sobre qué impulsa a Eclipse a insertar automáticamente una llamada de superclase en la implementación; pero luego no creo que ese sea el camino a seguir de todos modos, ya que esto siempre se puede eliminar.

En realidad, no puede hacer cumplir que un método debe llamar a la versión de la superclase con una palabra clave de Java, o algo por el estilo. Sospecho que sus excepciones simplemente provienen de algún código en la clase principal que verifica los invariantes esperados, o algo, que fueron invalidados por su enfoque. Tenga en cuenta que esto es sutilmente diferente de lanzar una excepción porque no pudo llamar super.onCreate().


8

Si quieres estar absolutamente seguro de que también se llama al método superclase, debes hacer un poco de truco: no permitas que se sobrescriba el método superclase, pero haz que llame a un método protegido anulable.

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

De esa manera, el usuario debe llamar a Super.foo () o Base.foo () y siempre será la versión de clase base ya que fue declarada como final. Las cosas específicas de la implementación están en impl_stuff (), que pueden anularse.


8

Para responder a su pregunta real, la creación automática de la llamada a super.onCreate () es una característica del complemento ADT. En java, no puede forzar directamente a una subclase a llamar a la súper implementación de un método, afaik (vea el patrón descrito en otras respuestas para una solución alternativa). Sin embargo, tenga en cuenta que en Android, no está instanciando objetos de Actividad (u objetos de Servicio) directamente: pasa un Intent al sistema y el sistema crea una instancia del objeto y llama a onCreate () sobre él (junto con otros métodos de ciclo de vida). Por lo tanto, el sistema tiene una referencia de objeto directa a la instancia de Actividad y puede verificar (presumiblemente) algún valor booleano que se establece en verdadero en la implementación de superclase de onCreate (). Aunque no sé exactamente cómo se implementa, probablemente se vea así:

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

Y en la clase de nivel "sistema" que recibe el Intent y crea una instancia del objeto Activity de él:

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

Mi suposición es que probablemente sea un poco más complejo que eso, pero entiendes la idea. Eclipse crea automáticamente la llamada porque el complemento ADT lo indica, para su comodidad. ¡Feliz codificación!


4

No hay nada en Java que obligue a llamar a super, y hay muchos ejemplos en los que no querría. El único lugar donde puede forzar la llamada de super es en constructores. Todos los constructores deben llamar a un constructor de superclase. Se insertará uno (el constructor sin argumentos) si no escribe uno explícitamente, y si no hay un constructor sin argumentos, debe llamarlo explícitamente.


3

Eclipse solo está siendo útil, recordándole que puede llamar a la implementación de superclase si lo desea.

probablemente obtenga un error porque no está haciendo algo necesario que hace la superclase, ya que no está llamando a su implementación.


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.