Quand NE PAS appeler la méthode super () lors de la substitution?


113

Lorsque je crée ma propre classe personnalisée Android, je suis extendsa classe native. Ensuite , quand je veux remplacer la méthode de base, je fais toujours appel super()méthode, tout comme je le fais toujours onCreate, onStopetc.

Et je pensais que c'était ça, car dès le début, l'équipe Android nous a conseillé de toujours appeler superchaque remplacement de méthode.

Mais, dans de nombreux livres, je peux voir que les développeurs, plus expérimentés que moi, omettent souvent d'appeler superet je doute vraiment qu'ils le fassent par manque de connaissances. Par exemple, regardez cette classe d'analyseur SAX de base où superest omis dans startElement, characterset 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 vous essayez de créer une méthode de remplacement via Eclipse ou tout autre IDE, elle supersera toujours créée dans le cadre d'un processus automatisé.

Ce n’était qu’un simple exemple. Les livres regorgent de codes similaires .

Comment savent-ils quand vous devez appeler superet quand vous pouvez l'omettre?

PS. Ne vous liez pas à cet exemple spécifique. C'était juste un exemple choisi au hasard parmi de nombreux exemples.

(Cela peut sembler une question de débutant, mais je suis vraiment confus.)


3
endElementLe document de l'API de l'API dit "Par défaut, ne faites rien. Les développeurs d'applications peuvent remplacer cette méthode ...", ce qui signifie que vous pouvez appeler super en toute sécurité car il ne fait "rien" mais vous n'êtes pas obligé et vous pouvez vraiment le remplacer. Vous pouvez souvent dire si vous devez / pouvez / ne devriez pas le faire si vous lisez la documentation de cette méthode.
zapl

1
Petit exemple: j'utilise onBackPressed () dans l'écran de démarrage, et je n'appelle PAS super pour qu'il ne sorte pas de splash, il désactive simplement le bouton.
Bojan Kogoj

@sandalone Désolé d'avoir demandé ici, mais avez-vous une expérience sur la façon de gérer la TVA avec la facturation intégrée à l'application, et dans quels pays cela est-il effectué automatiquement par Google, et dans lesquels je dois déclarer / payer manuellement la TVA? voir stackoverflow.com/questions/36506835/…
Vidar Vestnes

Réponses:


144

En appelant la superméthode, vous ne remplacez pas le comportement de la méthode, vous l' étendez .

Un appel à superexécutera toute logique que la classe que vous étendez a définie pour cette méthode. Tenez compte du fait que cela peut être important au moment où vous appelez l super'implémentation de votre méthode en remplaçant. Par exemple:

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

Un appel à B.save()exécutera la save()logique pour les deux Aet B, dans cet ordre particulier. Si vous n'appeliez pas à l' super.save()intérieur B.save(), vous A.save()ne seriez pas appelé. Et si vous appeliez super.save()après save(b), A.save()serait effectivement exécuté par la suite B.save().

Si vous voulez remplacer super le comportement de (c'est-à-dire ignorer complètement son implémentation et tout fournir vous-même), vous ne devriez pas appeler super.

Dans l' SAXParserexemple que vous fournissez, les implémentations de DefaultHandlerpour ces méthodes sont simplement vides, de sorte que les sous-classes peuvent les remplacer et fournir un comportement pour ces méthodes. Dans le javadoc de cette méthode, cela est également souligné.

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

À propos de l' super()appel par défaut dans le code généré par les IDE, comme @barsjuindiqué dans son commentaire, dans chaque constructeur il y a un appel implicite à super()(même si vous ne l'écrivez pas dans votre code), ce qui signifie, dans ce contexte, un appel à super' constructeur par défaut. Le IDEécrit simplement pour vous, mais il sera également appelé si vous le supprimez. Notez également que lors de l'implémentation de constructeurs, super()ou l'une de ses variantes avec des arguments (ie super(x,y,z)) ne peut être appelée qu'au tout début de la méthode.


14
Notez également que for constructors super()(le constructeur par défaut de la super classe) est toujours appelé, même si vous ne le spécifiez pas. Si la super classe n'a pas de constructeur par défaut, vous obtiendrez une erreur de compilation si vous n'appelez pas explicitement l'un des constructeurs de la super classe comme première instruction dans le constructeur de sous-classe.
barsju

1
Oui, c'est fondamentalement juste de la paresse - pour les méthodes que nous savons, ne faites rien, omettez-le simplement par souci de concision
Voo

1
Merci pour vos précieux commentaires, @barjsu, j'ai inclus ces détails dans la réponse.
Xavi López

16

Comment savent-ils quand vous devez appeler super et quand vous pouvez l'omettre d'appeler?

Habituellement, si une méthode API spéciale a une signification critique pour le cycle de vie du contexte du framework sous-jacent, elle sera toujours explicitement indiquée et mise en évidence dans la documentation de l'API, comme la Activity.onCreate()documentation de l' API . De plus, si l'API suit une conception robuste, elle doit lever des exceptions pour alerter le développeur consommateur au moment de la compilation du projet et s'assurer qu'elle ne générera pas d'erreur au moment de l'exécution.

Si cela n'est pas explicitement indiqué dans la documentation de l'API, il est tout à fait sûr pour le développeur consommateur de supposer que l'appel de la méthode API n'est pas obligatoire lors de la substitution. Il appartient au développeur consommateur de décider d'utiliser le comportement par défaut (appeler la superméthode) ou de le remplacer complètement.

Si la condition est autorisée (j'aime les logiciels open-source), le développeur consommateur peut toujours consulter le code source de l'API et voir comment la méthode est réellement écrite sous le capot. Vérifiez la Activity.onCreate()source et la DefaultHandler.startElement()source par exemple.


Merci de m'avoir expliqué des choses supplémentaires. Merci de me rappeler de vérifier le code source.
sandalone

7

Le test que vous devriez faire dans votre tête est:

"Est-ce que je veux que toutes les fonctionnalités de cette méthode soient faites pour moi, puis faire quelque chose après?" Si oui, vous souhaitez appeler super(), puis terminer votre méthode. Cela sera vrai pour les méthodes "importantes" telles que onDraw(), qui gère beaucoup de choses en arrière-plan.

Si vous ne voulez que certaines fonctionnalités (comme avec la plupart des méthodes que vous remplacerez), vous ne voudrez probablement pas appeler super().


3

Eh bien, Xavi a donné une meilleure réponse ... mais vous savez probablement ce que fait super()une méthode surchargée ... il annonce ce que vous avez fait avec le comportement par défaut.

par exemple:

onDraw() 

méthode en classe de vue en cas de substitution .. vous dessinez quelque chose avant de dire super.onDraw () il apparaît une fois la vue est entièrement utilisé .. alors voici l' appel superest nécessaire , car Android a des choses extrêmement importantes à faire (comme onCreate ())

mais en même temps

onLongClick()

lorsque vous remplacez cela, vous ne voulez pas appeler super car il ouvre une boîte de dialogue avec une liste d'options pour un EditText ou toute autre vue similaire .. C'est la différence de base .. vous avez le choix de le laisser quelques fois .. mais pour d'autres méthodes comme onCreate() , onStop()vous devriez laisser le système d'exploitation le gérer.


2

Je n'ai pas compris votre question clairement, mais si vous demandez pourquoi ne pas appeler la superméthode:

Il y a une raison pour appeler la superméthode: s'il n'y a pas de constructeur d'argument zéro dans la classe parente, il n'est pas possible de créer une classe enfant pour cela, donc soit vous devez garder un constructeur sans argument dans la classe parente, soit vous avez besoin pour définir super()l'instruction d'appel avec argument(how much argument constructor you have used in super class)en haut du constructeur de classe enfant.

J'espère que ça aide. Sinon, faites-le moi savoir.


2

J'ai implémenté une liste de tableaux de contraintes comme

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 vous regardez le code, il effectue simplement une vérification préalable avant de laisser la super classe effectuer l'ajout réel d'élément à la liste. Cela indique l'une des deux raisons de la substitution de méthode:

  1. Extensibilité où vous souhaitez étendre ce que la super classe peut faire
  2. Spécificité où vous souhaitez ajouter un comportement spécifique par polymorphisme, comme dans l'exemple commun du règne animal de la sémantique des mouvements où la façon dont les oiseaux se déplacent (volent) et les grenouilles (sautent) sont spécifiques à chaque sous-classe.

2

Pour ceux qui se demandaient également quelles méthodes remplacées d'Android Framework devraient appeler superet ont trouvé cette question - voici un indice actuel de 2019 - Android Studio 3+ vous dira quand vous en avez besoin .

entrez la description de l'image ici

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.