6 июл. 2015 г.

Полиморфные методы при вызове из конструктора.

Работы по расширению сознания полиморфизма продолжаются! Разберем один очень интересный пример. Но сперва надо вспомнить о том как вызываются конструкторы суперклассов.

Но что произойдет если вызвать переопределенный (полиморфный метод) в конструкторе суперкласса? Ведь как я уже не раз говорил, обычные методы всегда вызываются по версии объекта.

В принципе, мы можем в конструкторе суперкласса вызвать переопределенный метод подкласса. Но тут кроется коварная ошибка, ведь конструктор подкласса еще не был вызван. На момент такого вызова известно только то, что объекты суперкласса были проинициализированы. Но конструктор суперкласса является лишь очередным шагом на пути по­строения объекта подкласса, поля которого еще не были инициализированы его конструктором на момент вызова переопределенного метода подкласса из конструктора суперкласса. Поэтому переопределенный метод может перейти во «внешнюю» часть иерархии, то есть обратиться к данным подкласса, которые еще не были проинициализированы его конструктором, а этом может привести к манипуляции с неинициализированными данными, что это наверняка приведет к катастрофе. Хотя мы знаем что поля класса инициализируются значениями по умолчанию, но не известно на какие побочные эффекты мы можем напороться. Тут все зависит от звезд и их расположения по отношению к вашему коду :)

Мне кажется что предыдущий абзац уже вызвал побочный эффект в вашем мозгу? Да? Абзац полный? :)

Надеюсь что практика выведет ваш мозг к просветлению и понятию сути вопроса :)

PC001

Вывод у программы следующий:

PC002

Как видно из вывода программы, метод Cricle.drow() был вызван еще до вызова конструктора Crircle(). И можно было бы напороться на ошибку NullPointerException.

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

У происходящего есть и положительная сторона — по крайней мере, данные инициализируются значениями по умолчанию, а не каким-то мусором. Отрицательная это то, что компилятор молчал как партизан.

Подводя итог можно сделать вывод, что в конструкторах лучше избегать вызова переопределенных методов, дабы не наступить на грабли.

Но если очень хочется, то почему бы и нет :)

Grabli1

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

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