Страницы

Поиск по вопросам

суббота, 28 декабря 2019 г.

Вызов конструктора класса родителя в Java. В чём важность?

#java


Доброго времени суток всем. Читая книгу Брюса Эккеля, натолкнулся на следующий текст:


  Конечно, очень важно, чтобы подобъект базового класса был правильно
  инициализирован, и гарантировать это можно только одним способом:
  выполнить инициализацию в конструкторе, вызывая при этом конструктор
  базового класса, у которого есть необходимые знания и привилегии для
  проведения инициализации базового класса. Java автоматически вставляет
  вызовы конструктора базового класса в конструктор производного класса.


Помогите разобраться, почему же так важно вызвать конструктор базового класса для
класса наследника? И что будет если это не произойдёт (теоретически)? Спасибо.
    


Ответы

Ответ 1



Базовый класс по сути является как-бы частью наследника. Поэтому, если он не будет проинициализирован, то работать ничего не будет. Пример: public class A { protected int valA = 1; } public class B extends A { protected int valB = 2; public int getVal(){ return valB + valA; } } Наследование позволяет писать такую конструкцию. Если родительский класс не будет инициализировн, то в строке return valB + valA; будет неизвестно значение valA. Насколько я понимаю, не может быть ситуации, когда конструктор базового класса не вызовется (поправьте меня, если я ошибаюсь). Пример автоматического вызова конструкторов базовых классов.

Ответ 2



Это действительно важно. И вот почему. У базового класса может быть (и весьма часто бывает) какое-то внутренне состояние, которое нужно правильно инициализировать. И если этого не сделать, то ваш класс скорее всего не сможет правильно работать. Простой пример (код может содержать синтаксические ошибки - пишу без компилятора. Но суть, думаю, будет понятна): class Base { public Base(int size) { _someData = new int[size]; } protected int[] _someData; } class Child extends Base { public Child(int size) { // super(size); } void doSomething(int index, int value) { /// ... _someData[index] = value; } } Допустим, вы в конструкторе Child не вызвали конструктор предка Base. И тогда при вызове метода doSomething вы получите исключение, так как поле _someData не было инициализировано, так как его инициализация происходит в конструкторе предка, который вы не вызывали. Таких примеров, в том числе и куда более сложных, может быть очень много. К тому же ситуация может усугубляться, если вы создаете класс-наследник от класса, исходников которого у вас нет. Тогда вы вообще не можете знать, какие проблемы могут случиться с "недоинициализированным" классом до тех пор, пока с этими проблемами не столкнетесь

Ответ 3



В общем то в цитате из Эккеля и так все достаточно подробно написано. Класс-наследник только расширяет (дополняет) или изменяет функционал класса-родителя и не является самостоятельным классом, соответственно для работы класса-наследника необходимы инициализицации, производимые в базовом классе. Если этого не сделать, то вы получите различного вида экзепшены, указывающие на то, что именно не проинициализировано. Так же, если базовый класс не производит никакой инициализации и прочих действий, на которые опирается класс-наследник, то вызов его в конструкторе не требуется.

Ответ 4



Практически, если вы попытаетесь каким-то образом исключить вызов конструктора родительского класса, то компилятор сообщит об ошибке. Теоретически это означает, что у вас не будет корректно создан объект дочернего класса, потому что та часть объекта или некоторая функциональность, которая относится к родительскому подобъекту, не будет инициализирована или выполнена, и поведение программы будет неопределенным. Например, родительский объект может иметь private данные, которые кроме него самого никто инициализировать не может. Или родительский объект при своем конструировании может выделять и запрашивать какие-нибудь ресурсы, как, например, открытие файла или базы данных, установление соединения в сети, установка различных системных флагов и т.д.

Ответ 5



Хотелось бы расстроить людей которые вдруг посчитали в 2015 году что они разрешили этот вопрос. Мы можем взять и инициализировать поля если они конечно публичные в конструкторе производного и тогда вызов базового вроде как не нужен, но хохма вся в том что конструкторы срабатыват в порядке выведения классов от базового к конструктору класса объект которого мы создаём и всё это дело за нас делает компилятор если мы не создавали конструкторов с параметрами, в противном случаи всё это делать надо нам дабы не нарушать установленный не нами порядок, а вопрос почему это уже проще взять и застрелиться чем сидеть и думать почему. Это вопрос из разряда что было раньше курица, или яйцо. P.S да можно для себя принять такое объяснение что поля в базовом классе private и потому доступ есть только у конструктора базового класса и тогда необходимость налицо, также можно обосновать это тем что основная идея наследования состоит в том чтобы писать меньше кода и повторно использовать уже написанный.

Комментариев нет:

Отправить комментарий