JavaRush /Java блог /Random UA /Відмінності конструкторів від традиційних способів.
fog
18 рівень

Відмінності конструкторів від традиційних способів.

Стаття з групи Random UA
Конструктор - це особливий спосіб, який призначається для первинної установки значень полів об'єкта. На перший погляд, конструктори об'єктів не сильно відрізняються від звичайних методів об'єкта. І справді всередині конструктора ми можемо робити все те ж, що й у звичайних методах об'єкта: виводити текст у консоль, звертатися до всіх полів та методів нового об'єкта, викидати винятки тощо. Як і звичайні методи, конструктори можуть мати аргументи. Як і перевантажених методів, конструкторів може бути кілька з різними сигнатурами. Так само як і дженерик-методи, конструктори можуть бути параметризовані змінними типами. Навіть якщо ми заглянемо в байт-код, що генерується компілятором, у місці де має бути виклик конструктора, ми виявимо звернення до деякого методу з ім'ям <init>виклик якого не відрізняється від виклику інших методів об'єкта. А знайшовши байт-код цього методу, ми виявимо, що він містить результат компіляції нашого конструктора. Здається, що відмінностей від звичайних методів небагато, але вони є, і досить суттєві. Спочатку давайте розберемося, а навіщо нам власне потрібні конструктори? Для зберігання та обробки будь-яких даних, чи то примітивні типи, масиви, чи об'єкти нам необхідний деякий обсяг пам'яті. Це можуть бути регістри процесора, місце на стеку, або шматочок простору, виділений в секції даних процесу, або динамічно розміщується частини пам'яті (купі). У багатьох мовах програмування, з метою прискорення, при запиті програмою нового шматочка пам'яті, пам'ять віддавалася програмі не відчищеною, і могла містити довільні дані, які були збережені в цьому осередку пам'яті раніше. Підготовка та запис у такий шматок пам'яті необхідних значень, щоб у результаті там виявилася якась осмислена структура даних, лягала цілком на плечі програміста. Цілком звичайно програмісти хотіли полегшити собі життя і писали підпрограми для ініціалізації (тобто установки початкових значень) для структур даних, що часто використовуються. Такі підпрограми застосовувалися майже завжди, тому творці мови Java, вирішабо зробити подібні підпрограми ініціалізації обов'язковими для виклику під час створення об'єктів, і назвали їх конструкторами . Коли Java створюється новий об'єкт відбувається таке: Спочатку менеджер пам'яті Java виділяє обсяг пам'яті необхідний розміщення об'єкта. У цьому враховуються як поля оголошені у класі створюваного об'єкта, але як і поля оголошені переважають у всіх предках цього. Додатково в цей обсяг включається простір для розміщення структур, які використовуються Java-машиною для внутрішніх потреб. Всі поля такої "заготівлі" автоматично встановлюються в дефолтні значення - nullдля типів посилань, 0для чисел і falseдляboolean. Після цього автоматично викликається конструктор класу, завдання якого встановити початкові значення полів об'єкта. Якщо у звичайному методі перший оператор може бути будь-яким, то конструктор має набагато менше свободи. Першим оператором конструктора може бути або явний виклик іншого конструктора тієї самої класу, або явний чи неявний виклик конструктора батьківського класу. Явний виклик конструкторів того ж класу здійснюється за допомогою ключового слова, thisза яким слідує набір аргументів, укладений у дужки. Явний виклик конструктора батьківського класу здійснюється так само, але при цьому використовується ключове слово super. У аргументах явного виклику конструктора тієї самої, чи батьківського класу не можна звертатися до полів і методів об'єкта, як і використовувати ключові слова thisі super, оскільки явний виклик конструктора вводить статичний контекст. Для неявного виклику конструктора батьківського класу писати нічого не треба, але при цьому неявно викликається конструктор за замовчуванням, який повинен існувати і бути видимим для поточного класу. При цьому слід мати на увазі, що якщо ланцюжок виклику батьківських конструкторів перерветься до того, як конструктор класу, що Objectзнаходиться на вершині ланцюжка, успішно завершить свою роботу, то об'єкт не буде фіналізованим, тобто метод finalize()такого об'єкта ніколи викликаний не буде. Після завершення роботи конструктора батьківського класу управління неявно передається на блоки ініціалізаторів екземпляра та ініціалізатори полів екземпляра поточного класу. Ініціалізатори виконуються в порядку, в якому вони зустрічаються в тексті програми. Лише після завершення роботи ініціалізаторів управління передається частині конструктора, що залишилася. Інші особливості конструкторів стосуються моделі пам'яті Java. Якщо клас, чи з його предків, перевизначає метод finalize(), завершення роботи конструктора відбудеться до ( happens-before ) запуску методу finalize(). Якщо який-небудь потік побачив посилання на об'єкт після завершення роботи конструктора, то гарантується, що цей потік побачить коректно ініціалізовані finalполя об'єкта, ініціалізація яких відбулася до завершення роботи конструктора.
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ