¿Cuándo NO llamar al método super () al anular?

113

Cuando creo mi propia clase personalizada de Android, extendsu clase nativa. Entonces cuando quiero anular el método de base, siempre llamo super()método, al igual que siempre hago en onCreate, onStop, etc.

Y pensé que esto era todo, ya que desde el principio el equipo de Android nos aconsejó que siempre invocáramos supercada anulación de método.

Pero, en muchos libros puedo ver que los desarrolladores, con más experiencia que yo, a menudo omiten las llamadas supery realmente dudo que lo hagan por falta de conocimiento. Por ejemplo, observe esta clase de analizador SAX básica donde superse omite en startElement, charactersy 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
        }
    }
}

Si intenta crear cualquier método de anulación a través de Eclipse o cualquier otro IDE, supersiempre se creará como parte del proceso automatizado.

Este fue solo un ejemplo simple. Los libros están llenos de códigos similares .

¿Cómo saben cuándo debe llamar supery cuándo puede omitirlo?

PD. No se limite a este ejemplo específico. Fue solo un ejemplo elegido al azar de muchos ejemplos.

(Esto puede parecer una pregunta para principiantes, pero estoy realmente confundido).

sandalias
fuente
3
endElementEl documento de la API dice "De forma predeterminada, no hacer nada. Los escritores de aplicaciones pueden anular este método ...", lo que significa que puede llamar de forma segura a super porque no hace "nada", pero no es necesario y realmente puede anularlo. A menudo puede saber si tiene que / puede / no debe hacerlo si lee el documento de ese método.
zapl
1
Pequeño ejemplo: utilizo onBackPressed () en la pantalla de bienvenida, y NO llamo a super para que no salga de la pantalla, simplemente desactiva el botón.
Bojan Kogoj
@sandalone Perdón por preguntar aquí, pero ¿tiene alguna experiencia sobre cómo manejar el impuesto del IVA con la facturación integrada en la aplicación, y en qué países Google lo hace automáticamente y en cuáles debo informar / pagar manualmente el impuesto del IVA? ver stackoverflow.com/questions/36506835/…
Vidar Vestnes

Respuestas:

144

Al llamar al supermétodo, no está anulando el comportamiento del método, lo está extendiendo .

Una llamada a superejecutará cualquier lógica que la clase que está extendiendo haya definido para ese método. Tenga en cuenta que podría ser importante en el momento en que llame a superla implementación de su método overriding. Por ejemplo:

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

Una llamada a B.save()realizará la save()lógica para ambos Ay B, en este orden en particular. Si no estuvieras llamando super.save()adentro B.save(), A.save()no te llamarían. Y si llama super.save()después save(b), A.save()se realizará efectivamente después B.save().

Si desea anular super el comportamiento (es decir, ignorar completamente su implementación y proporcionarlo todo usted mismo), no debería llamar super.

En el SAXParserejemplo que proporciona, las implementaciones de DefaultHandlerpara esos métodos están simplemente vacías, por lo que las subclases pueden anularlas y proporcionar un comportamiento para esos métodos. En el javadoc para este método esto también se señala.

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

Acerca de la super()llamada predeterminada en el código generado por los IDE, como se @barsjuseñala en su comentario, en cada constructor hay una llamada implícita a super()(incluso si no la escribe en su código), lo que significa, en ese contexto, una llamada a super' s constructor predeterminado. El IDEsimplemente lo escribe para usted, sino que también se llama si se la ha quitado. También observe que cuando se implementan constructores, super()o cualquiera de sus variantes con argumentos (es decir super(x,y,z)), solo se puede llamar al principio del método.

Xavi López
fuente
14
Además, tenga en cuenta que para los constructores super()(el constructor predeterminado de la superclase) siempre se llama, incluso si no lo especifica. Si la superclase no tiene un constructor predeterminado, obtendrá un error de compilación si no llama explícitamente a uno de los constructores de la superclase como su primera declaración en el constructor de subclase.
Barsju
1
Sí, es básicamente solo pereza, para los métodos que sabemos que no hacen nada, simplemente omítelo por brevedad
Voo
1
Gracias por tus valiosos comentarios, @barjsu, he incluido estos detalles en la respuesta.
Xavi López
16

¿Cómo saben cuándo debe llamar a super y cuándo puede omitirlo?

Por lo general, si un método API especial tiene un significado crítico para el ciclo de vida del contexto del marco subyacente, siempre se indicará y destacará explícitamente en la documentación de la API, como la Activity.onCreate()documentación de la API . Además, si la API sigue un diseño robusto, debería generar algunas excepciones para alertar al desarrollador consumidor en el tiempo de compilación del proyecto y asegurarse de que no generará una falla en el tiempo de ejecución.

Si esto no se indica explícitamente en la documentación de la API, entonces es bastante seguro para el desarrollador consumidor asumir que no es obligatorio llamar al método API al anularlo. Depende del desarrollador consumidor decidir si utilizar el comportamiento predeterminado (llamar al supermétodo) o anularlo por completo.

Si la condición está permitida (me encanta el software de código abierto), el desarrollador consumidor siempre puede consultar el código fuente de la API y ver cómo está escrito realmente el método bajo el capó. Ver Activity.onCreate()fuente y la DefaultHandler.startElement()fuente, por ejemplo.

yorkw
fuente
Gracias por explicarme cosas adicionales. Gracias por recordarme que revise el código fuente.
sandalia
7

La prueba que debes hacer en tu cabeza es:

"¿Quiero hacerme todas las funciones de este método y luego hacer algo?" Si es así, entonces desea llamar super()y luego terminar su método. Esto será cierto para métodos "importantes" comoonDraw() , que maneja muchas cosas en segundo plano.

Si solo desea parte de la funcionalidad (como con la mayoría de los métodos que anulará), probablemente no desee llamar super().

Miguel
fuente
3

Bueno, Xavi dio una mejor respuesta ... pero probablemente sepas lo que hacesuper() cuando se le llama en un método anulado ... anuncia lo que ha hecho con el comportamiento predeterminado ...

p.ej:

onDraw() 

método en la clase de vista cuando se anula ... dibuja algo antes de decir super.onDraw () aparece una vez que la vista está completamente dibujada ... así que aquí superes necesario llamar ya que Android tiene algunas cosas críticamente importantes que hacer (como onCreate ())

pero al mismo tiempo

onLongClick()

cuando anula esto, no quiere llamar a super porque abre un cuadro de diálogo con una lista de opciones para un EditText o cualquier otra vista similar .. Esa es la diferencia básica .. tiene la opción de dejarla algunas veces .. pero por otros métodos como onCreate() , onStop()usted debería dejar que el sistema operativo lo maneje ..

ngesh
fuente
2

No recibí su pregunta claramente, pero si está preguntando por qué no llamar al supermétodo:

Hay una razón para llamar al supermétodo: si no hay un constructor de argumento cero en la clase principal, entonces no es posible crear una clase secundaria para eso, por lo que debe mantener un constructor sin argumentos en la clase principal o necesita para definir la super()instrucción de llamada argument(how much argument constructor you have used in super class)en la parte superior del constructor de la clase secundaria.

Espero que esto ayude. Si no, avíseme.

Vikas Gupta
fuente
2

Implementé una lista de matriz de restricciones como

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

Si observa el código, simplemente realiza una verificación previa antes de permitir que la superclase realice la adición real del elemento a la lista. Esto indica una de las dos razones por las que se reemplaza el método:

  1. Extensibilidad donde desee ampliar lo que puede hacer la superclase
  2. Especificidad donde desea agregar un comportamiento específico a través del polimorfismo, como en el ejemplo común del reino animal de la semántica de movimiento, donde la forma en que las aves se mueven (vuelan) y las ranas se mueven (saltan) son específicas para cada subclase.
maress
fuente
2

Para aquellos que también se preguntaron qué métodos anulados de Android Framework deberían llamar supery encontraron esta pregunta (aquí hay una pista actual de 2019), Android Studio 3+ le dirá cuándo lo necesita .

ingrese la descripción de la imagen aquí

dominik
fuente