Когда НЕ переписывать метод super () при переопределении?

Когда я создаю свой собственный пользовательский класс Android, я extend его родной класс. Затем, когда я хочу переопределить базовый метод, я всегда вызываю метод super() , как и всегда в onCreate , onStop и т. Д.

И я подумал, что это так, так как с самого начала команда Android советовала нам всегда называть super при каждом переопределении метода.

Но во многих книгах я вижу, что разработчики, более опытные, чем я, часто опускают вызов super и я действительно сомневаюсь, что они делают это как недостаток знаний. Например, посмотрите на этот базовый класс парсеров SAX, где super опущен в startElement , characters и 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 } } } 

Если вы попытаетесь создать любой метод переопределения через Eclipse или любую другую IDE, super всегда будет создаваться как часть автоматизированного процесса.

Это был простой пример. Книги полны аналогичного кода .

Как они узнают, когда вы должны назвать super и когда вы можете опустить его?

PS. Не связывайтесь с этим конкретным примером. Это был просто случай, случайно выбранный из многих примеров.

(Это может показаться новичком, но я действительно смущен.)

Solutions Collecting From Web of "Когда НЕ переписывать метод super () при переопределении?"

super метод super , вы не переопределяете поведение метода, вы его расширяете .

Вызов super будет выполнять любую логику, которую класс, который вы расширяете, определил для этого метода. Учтите, что это может быть важно в тот момент, когда вы называете реализацию super в своем методе переопределения. Например:

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

Вызов B.save() будет выполнять логику save() для A и B в этом конкретном порядке. Если вы не super.save() внутри B.save() , A.save() не вызывался. И если вы вызвали super.save() после save(b) , A.save() будет эффективно выполняться после B.save() .

Если вы хотите переопределить поведение super (то есть полностью игнорировать его реализацию и предоставить все это самостоятельно), вы не должны называть super .

В приведенном SAXParser примере SAXParser реализации DefaultHandler для этих методов просто пусты, поэтому подклассы могут переопределять их и обеспечивать поведение для этих методов. В javadoc для этого метода это также указано.

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

О вызове super() умолчанию в коде, сгенерированном IDE, как отметил @barsju в своем комментарии, в каждом конструкторе есть неявный вызов super() (даже если вы не записываете его в свой код), что означает, В этом контексте – вызов конструктора по умолчанию super . IDE просто записывает его для вас, но его также вызывают, если вы его удалите. Также обратите внимание, что при реализации конструкторов super() или любой из его вариантов с аргументами (т. super(x,y,z) ) можно вызывать только в самом начале метода.

Как они узнают, когда вы должны назвать супер, и когда вы можете опустить его?

Обычно, если специальный метод API имеет критическое значение для жизненного цикла базового контекста, он всегда будет явно указан и выделен в документации API, например документации API Activity.onCreate() . Более того, если API следует за надежной конструкцией, он должен бросить некоторые исключения, чтобы предупредить разработчика-потребителя во время компиляции проекта и убедиться, что он не будет генерировать ошибку во время выполнения.

Если это явно не указано в документации API, то для разработчика-потребителя совершенно безопасно предположить, что метод API не обязательно для вызова при его переопределении. Разработчик потребителя должен решить, использовать ли поведение по умолчанию (вызвать метод super ) или полностью переопределить его.

Если условие разрешено (я люблю программное обеспечение с открытым исходным кодом), потребительский разработчик всегда может проверить исходный код API и посмотреть, как метод фактически написан под капотом. Проверьте источник Activity.onCreate() источник DefaultHandler.startElement() например.

Тестирование, которое вы должны сделать в своей голове:

«Я хочу, чтобы все функции этого метода выполнялись для меня, а затем потом что-то делать?» Если да, то вы хотите вызвать super() , а затем закончить свой метод. Это будет верно для «важных» методов, таких как onDraw() , которые обрабатывают множество вещей в фоновом режиме.

Если вам нужна только часть функций (как и в большинстве методов, которые вы переопределите), вы, вероятно, не хотите называть super() .

Ну, Хави дал лучший ответ .. но вы, вероятно, знаете, что делает super() при вызове в переопределенном методе … он рекламирует, что вы сделали с поведением по умолчанию.

например:

 onDraw() 

Метод в классе вида при переопределении .. вы рисуете что-то перед тем, как сказать super.onDraw () появляется, как только представление полностью нарисовано .. поэтому здесь вызов super необходим, так как у android есть некоторые важные важные вещи (например, onCreate ())

но в то же время

 onLongClick() 

Когда вы переопределяете это, вы не хотите называть супер, потому что он вызывает диалог со списком параметров для EditText или любого другого подобного вида. Это базовый diff .. у вас есть выбор, чтобы оставить его несколько раз .. но для Другие методы, такие как onCreate() , onStop() вы должны позволить ОС обрабатывать это.

Я не понял ваш вопрос четко, но если вы спрашиваете, почему бы не назвать метод super :

Существует причина для вызова super метода: если в родительском классе нет конструктора нулевых аргументов, невозможно создать для него дочерний класс, поэтому либо вам необходимо сохранить конструктор аргументов в родительском классе, либо вы Необходимо определить оператор super() вызывающий с argument(how much argument constructor you have used in super class) в верхней части конструктора дочернего класса.

Надеюсь, это поможет. Если нет, дайте мне знать.

Я применил список массивов ограничений, например

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

Если вы посмотрите на код, он просто выполняет некоторую предварительную проверку, прежде чем позволить супер классу выполнить фактическое добавление элемента в список. Это говорит о одной из двух кратных причин переопределения метода:

  1. Расширяемость, в которой вы хотите расширить то, что может сделать суперкласс
  2. Специфичность, в которой вы хотите добавить определенное поведение через полиморфизм, например, в общий пример царства животных в семантике перемещения, где перемещение птиц (перемещение) и движение лягушек (прыжок) зависят от каждого подкласса.