Контакти

Конструктори Java Навіщо потрібні конструктори? Поняття конструктора за умовчанням

1. Поняття конструктора за умовчанням

Конструктор за замовчуванням (default constructor) – конструктор, який не має параметрів. Конструктор за замовчуванням може оголошуватися у класі явним чином або генеруватись автоматично.

У найбільш загальному випадку для класу ClassName конструктор за замовчуванням має такий вигляд:

class ClassName (... // оголошення конструктора ClassName() ( // Тіло конструктора // ... } ... }
2. У яких випадках конструктор за умовчанням генерується в класі автоматично, а в яких ні? приклад

Якщо в класі не оголосити жодного конструктора, то генеруватиметься конструктор за замовчуванням. Тобто конструктор за замовчуванням генерується в класі автоматично тільки в тому випадку, якщо клас не містить реалізації інших конструкторів. Якщо клас містить реалізацію хоча б одного конструктора з параметрами, то, щоб оголосити за замовчуванням конструктор, його потрібно оголошувати в класі явним чином.

Наприклад.У наступному оголошенні класу конструктор за замовчуванням генерується автоматично

class CMyClass ( int d; int GetD() ( return d; ) void SetD( int nd) (d = nd; ))

Наведений вище код означає, що можна оголошувати об'єкт класу з використанням конструктора за замовчуванням:

// працює, так як у класі більше не реалізовано жодного конструктора CMyClass mc = new CMyClass();

Якщо до тіла CMyClass додати хоча б один інший конструктор (наприклад, конструктор з одним параметром), то конструктор за замовчуванням автоматично генеруватися не буде

class CMyClass ( int d; // конструктор за замовчуванням не генерується автоматично CMyClass( int nd) (d = nd;) int GetD() ( return d; ) void Set( int nd) (d = nd; ))

Після наведеної вище реалізації оголосити об'єкт з використанням конструктора за умовчанням не вдасться. Однак, можна оголосити об'єкт із використанням конструктора з одним параметром

// помилка компіляції, оскільки у класі вже оголошено інший конструктор // CMyClass mc = New CMyClass(); CMyClass mc2 = new CMyClass(7); // а цей код працює

В результаті виконання вищенаведеного рядка буде видано помилку компіляції:

The constructor CMyClass() is undefined

Для того, щоб мати реалізацію конструктора за умовчанням та оголошувати об'єкт класу з використанням конструктора за умовчанням, його потрібно ставити явно. Це може бути, наприклад, так

class CMyClass ( int d; // явне оголошення конструктора за умовчанням CMyClass() ( d = 0; ) // оголошення конструктора з 1 параметром, CMyClass( int nd) (d = nd;) int GetD() ( return d; ) void Set( int nd) (d = nd; ))

Після такої реалізації можна створювати екземпляр класу з використанням двох конструкторів, наприклад

CMyClass mc = new CMyClass(); // Викликається конструктор за замовчуванням mc.d = 25; CMyClass mc2 = new CMyClass(5); // Викликається конструктор з 1 параметром

3. Виклик конструкторів із інших конструкторів. приклад

Мова програмування Java дозволяє здійснювати виклик конструкторів класу з іншого конструктора цього класу. Для цього використовується ключове слово this, яке є посиланням на поточний клас.

приклад.У прикладі демонструється використання класу CPixel, який реалізує піксел на екрані монітора.

// Клас, який реалізує піксел на екрані монітора public class CPixel ( // внутрішні змінні класу private int x, y; // координати пікселя private int color; // колір пікселу // конструктор без параметрів (за замовчуванням конструктор) CPixel() ( x = y = color = 0; ) // конструктор з 2 параметрами, які ініціалізують лише координати CPixel( int _x, int _y) (x = _x; y = _y; color = 0; ) // конструктор з 1 параметром, який ініціалізує лише колір CPixel( int _color) (color = _color; x = y = 0; ) // конструктор із 3 параметрами, який викликає конструктор із 2 параметрами CPixel ( int _x, int _y, int _color) ( // Виклик конструктора з 2 параметрами: обов'язково перша операція і тільки один раз this(_x, _y); //this(_color); // повторний виклик конструктора заборонено this.color = _color; // так можна ) // методи доступу int GetX() ( return x; ) int GetY() ( return y; ) int GetColor() ( return color; )

Використання класу CPixel в іншому програмному коді (методі)

CPixel cp1 = new CPixel(2,8); // Виклик конструктора з 2 параметрами CPixel cp2 = new CPixel(3,5,8); // Виклик конструктора, який викличе інший конструктор int d; d = cp1.GetX(); // d = 2 d = cp2. GetColor (); // d = 8 d = cp2. GetY (); // d = 5 ...

4. Які обмеження (вимоги) накладаються на виклик інших конструкторів із конструктора класу?

Щоб коректно викликати інші конструктори з конструктора класу, потрібно дотримуватись таких вимог (обмежень):

  • викликати можна лише один інший конструктор класу. Викликати двох і більше інших конструкторів цього класу заборонено. Це випливає з логіки, що конструктор класу призначений для створення об'єкта класу лише один раз (а не два і більше разів);
  • виклик іншого конструктора повинен бути першою операцією в конструкторі, що викликає. Якщо у конструкторі виклик іншого конструктора реалізувати другий (третьої і т.д.) операцією, то компілятор видасть помилку.

Метод у Java- це комплекс виразів, сукупність яких дозволяє виконати певну операцію. Так, наприклад, при викликі методу System.out.println() система виконує ряд команд для виведення повідомлення на консоль.

На даному етапі ви освоїте техніку створення власних методів з або без значень, що повертаються, виклику методів із зазначенням або без вказівки параметрів, і виділення методів при розробці програми.

Створення методу

Нижче розглянуто приклад, що ілюструє синтаксис методу, як у Java створити метод.

Синтаксис

public static int methodName(int a, int b) ( // тіло )
  • public static – модифікатор;
  • int - тип, що повертається;
  • methodName - ім'я методу;
  • a, b – формальні параметри;
  • int a, int b – перелік параметрів.

Визначення методу представлено заголовком та тілом методу. Те саме ми можемо спостерігати в наступному синтаксисі створення методу.

Синтаксис

modifier returnType nameOfMethod (Parameter List) ( // тіло методу )

Наведений вище синтаксис включає:

  • modifier – визначає тип доступу для методу та можливість його використання.
  • returnType – метод може повернути значення.
  • nameOfMethod – вказує ім'я методу. Сигнатура методу включає ім'я методу та перелік параметрів.
  • Parameter List – перелік параметрів представлений типом, порядком та кількістю параметрів методу. Ця опція задається довільно, у методі може бути нульовий параметр.
  • method body – тіло методу визначає метод роботи з командами.

приклад

/* фрагмент коду повертає мінімальне між двома числами */ public static int minFunction(int n1, int n2) ( int min; if (n1 > n2) min = n2; else min = n1; return min; )

Виклик методу

Перед використанням методу необхідно викликати. Існує два способи виклику методу в Java, тобто. Спосіб здійснює повернення значення або не виробляє (відсутнє повертає значення).

Алгоритм виклику методу є досить простим. Коли програма здійснює Java виклик методу, програмне управління передається викликаному методу. Даний викликаний метод потім повертає управління клієнтові, що викликає, у двох випадках, якщо:

  • виконується оператор повернення;
  • досягнуто закриває фігурна дужка закінчення методу.

Метод повернення типу void здійснює виклик команди. Розглянемо приклад:

System.out.!");

Метод повернення значення може бути проілюстрований таким прикладом:

Int result = sum(6, 9);

Приклад нижче демонструє спосіб визначення та виклику методу Java.

приклад

public class ExampleMinNumber ( public static void main(String args) ( int a = 11; int b = 6; int c = minFunction(a, b); System.out.println("Мінімальне значення = " + c); ) / * Повертає мінімум із двох чисел */ public static int minFunction(int n1, int n2) ( int min; if (n1 >

Мінімальне значення = 6

Ключове слово void

Ключове слово void Java дозволяє нам створити методи, що не роблять повернення значення. У прикладі, наведеному далі, нами було розглянуто метод типу void – methodRankPoints. Методи типу void в Java не здійснюють повернення будь-яких значень. Виклик методу типу void виконується командою, тобто. methodRankPoints(255.7);. Це java-вираз, який закінчується крапкою з комою, як показано в прикладі нижче:

приклад

public class ExampleVoid ( public static void main(String args) ( methodRankPoints(255.7); ) public static void methodRankPoints(double points) ( if (points >= 202.5) ( System.out.println("Ранг A1") if (points >= 122.4) ( System.out.println("Ранг A2"); )else ( System.out.println("Ранг A3"); ) ) )

У результаті буде отримано наступний результат:

Ранг A1

Передача параметрів за значенням у Java

При виконанні процесу, що викликає, проводиться в Java передача аргументів. Процедура повинна здійснюватися згідно з порядком, передбаченим відповідними параметрами у специфікації методу. Передача параметрів може здійснюватися за значенням або посиланням.

У Java передача параметрів за значенням означає виклик методу з параметром. За рахунок цього здійснюється передача значення аргументу параметру.

приклад

Наступна програма показує приклад передачі параметра за значенням. Значення аргументів залишаються незмінними навіть після виклику методу.

Public class swappingExample ( public static void main(String args) ( int a = 30; int b = 45; System.out.println("Перед тим як передати, значення аргументів a = " + a + " і b = " + b ); // Виклик методу передачі swapFunction(a, b); System.out.println("\nЗараз, до і після передачі значення аргументів "); і b = "+ b); c = a; a = b; b = c; System.out.println("Після заміни: a = " + a + " b = " + b); ) )

Отримаємо наступний результат:

Перед тим як передати значення аргументів a = 30 і b = 45 До заміни: a = 30 b = 45 Після заміни: a = 45 b = 30 Зараз, до і після передачі значення аргументів залишилися незмінними, a = 30 і b = 45

Перевантаження методів

Перевантаження методів у Java- Випадок, коли в класі присутні два і більше методи з однаковим ім'ям, але різними параметрами. Цей процес відмінний від перевизначення методів. При перевизначенні методів метод характеризується аналогічним ім'ям, типом, числом параметрів і т.д.

Розглянемо приклад, представлений вище щодо мінімальних чисел целочисленного типу. Припустимо, ми хочемо визначити мінімальне число подвійного типу. В даному випадку буде представлено концепцію навантаження для створення двох і більше методів з однаковим ім'ям, але різними параметрами.

Розглянутий приклад пояснює сказане вище.

приклад

public class ExampleOverloading ( public static void main(String args) ( int a = 7; int b = 3; double c = 5.1; double d = 7.2; int result1 = minFunction(a, b); // така ж функція з іншими параметрами double result2 = minFunction(c, d); System.out.println("Мінімальне значення = " + result1); (int n1, int n2) ( int min; if (n1 > n2) min = n2; else min = n1; return min; ) // для double public static double minFunction(double n1, double n2) ( double min; if (n1 > n2) min = n2; else min = n1; return min;

У результаті буде отримано наступний результат:

Мінімальне значення = 3 Мінімальне значення = 5.1

Методи навантаження роблять програму читаної. Таким чином, представлено два методи з однаковим ім'ям, але різними параметрами. Внаслідок чого ми отримали мінімальні int число та число double типу.

Використання аргументів командного рядка

Під час роботи програми вам може знадобитися передачу певної інформації. Це може бути зроблено Java за рахунок передачі аргументів командного рядка в main().

Java аргумент командного рядка представляє інформацію, яка безпосередньо слідує за ім'ям програми в командному рядку при її виконанні. Отримання доступу до аргументів командного рядка в java-програмі не є складним. Вони зберігаються як рядки в масиві рядків, переданому в main().

приклад

Програма нижче відображає всі викликані аргументи командного рядка.

Public class CommandLine ( public static void main (String args) ( for (int i = 0; i

Спробуйте виконати цю програму, як показано далі:

$java CommandLine це командний рядок 300 -200

У результаті буде отримано наступний результат:

Args: це args: командна args: рядок args: 300 args: -200

Конструктор у Java

У Java конструкторініціалізує об'єкт під час його створення. Його ім'я аналогічне імені класу, а синтаксис подібний до синтаксису методу. Однак, на відміну від останнього, в конструкторі відсутнє значення, що повертається.

Як правило, конструктор Java може використовуватися для присвоєння вихідного значення змінних екземпляра, що визначаються класом, або для виконання будь-яких інших процедур запуску, необхідних для створення повністю сформованого об'єкта.

Конструктори присутні у всіх класах, незалежно від їх вказівки, тому що Java автоматично надає конструктор за замовчуванням, який ініціалізує всі змінні членів класу до нуля. Разом з цим, після того, як ви визначите власний конструктор, конструктор за замовчуванням більше не буде задіяний.

приклад

У наведеному нижче прикладі розглянуто використання конструктора класу без параметрів.

// Простий конструктор. class MyClass ( int x; // Далі слідує конструктор MyClass() ( x = 10; ) )

Для ініціалізації об'єктів вам необхідно здійснити виклик конструктора згідно з наступним прикладом.

Public class ConsDemo ( public static void main(String args) ( MyClass t1 = new MyClass(); MyClass t2 = new MyClass();

Отримаємо результат:

Параметризований конструктор

Найчастіше вам знадобиться конструктор, який приймає один і більше параметрів. Додавання параметрів до конструктора аналогічно їх додавання в метод, слід лише внести в круглі дужки після імені конструктора.

приклад

// Простий конструктор. class MyClass ( int x; // Нижче конструктор MyClass (int i) ( x = i; ) )

З метою ініціалізації об'єктів вам знадобиться викликати конструктор згідно з таким прикладом.

Public class ConsDemo ( public static void main(String args) ( MyClass t1 = новий MyClass(10); MyClass t2 = новий MyClass(20); System.out.println(t1.x + " " + t2.x); ) )

Отримаємо наступний результат:

Ключове слово this

Ключове слово this- використовується посилання на поточний клас з урахуванням методу чи конструктора екземпляра. Використовуючи це в Java, Ви можете посилатися на екземпляри класу, такі як конструктори, змінні та методи.

Примітка:Ключове слово цього використовується тільки у складі методів або конструкторів екземпляра.

Як правило, ключове слово this в Java використовується для:

  • диференціювання між змінними екземпляра та локальними змінними у разі, якщо у них однакові імена, у складі конструктора чи методу.
class Student ( int age; Student(int age) ( this.age = age; ) )
  • виклику конструктора одного типу (параметризованого конструктора чи конструктора за замовчуванням) з іншого у складі класу. Цей процес також називається явного виклику конструктора.
class Student ( int age Student() ( this(20); ) Student(int age) ( this.age = age; ) )

приклад

Public class This_Example ( // Ініціалізація змінної num int num = 11; This_Example() ( System.out.println("Це приклад програми з ключовим словом this"); ) This_Example(int num) ( // Виклик конструктора за замовчуванням this( ) // Присвоєння локальної змінної num змінної екземпляра num this.num = num; ) public void greet() ( System.out.println("Привіт! Ласкаво просимо в ProgLang!"); Локальна змінна num int num = 20; // Виклик методу класу greet this.greet(); // Висновок локальної змінної. .out.println("Значення змінної екземпляра num: " + this.num); ) public static void main(String args) ( // Ініціалізація класу This_Example obj1 = new This_Example(); // Виклик методу print obj1.print() // Передача нового значення змінної num через параметризований конструктор This_Example obj2 = new This_Example(30);// Ви поклик знову методу print obj2.print(); )

У результаті буде отримано наступний результат:

Це приклад програми з ключовим словом це Привіт! Ласкаво просимо в ProgLang! Значення локальної змінної num: 22 Значення змінної екземпляра num: 11 Це приклад програми з ключовим словом this Привіт! Ласкаво просимо в ProgLang! Значення локальної змінної num: 22 Значення змінної екземпляра num: 30

Аргументи змінної (var-args)

JDK 1.5 та вище дозволяє передавати методу змінну кількість аргументів одного типу. Параметр методу оголошується так:

TypeName... parameterName

При оголошенні методу Ви вказуєте тип, за яким слідує крапка (...). У методі може бути лише один параметр змінної довжини, і цей параметр має бути останнім параметром. Будь-які регулярні параметри мають передувати йому.

приклад

public class VarargsDemo ( public static void main(String args) ( // Виклик методу зі змінною args printMax(27, 11, 11, 5, 77.1); printMax(new double(10, 11, 12, 77, 71))); ) public static void printMax(double... numbers) ( if (numbers.length == 0) ( System.out.println("Жоден аргумент не передається"); return; ) double result = numbers; for (int i = 1; i result) result = numbers[i];

У результаті буде отримано наступний результат:

Максимальне значення 77.1 Максимальне значення 77.0

Метод finalize()

Метод finalize()- метод, який буде викликатись безпосередньо перед остаточним знищенням об'єкта збирачем сміття. (Фінализатором). Java finalize() може бути використаний для забезпечення чистого завершення об'єкта.

Наприклад, ми можете використовувати finalize(), щоб переконатися, що відкритий файл, що належить даному об'єкту, був закритий.

Для додавання фіналізатора до класу, вам просто слід визначити метод finalize() у Java. Середовище виконання Java здійснює виклик цього методу безпосередньо перед обробкою об'єкта цього класу.

У складі методу finalize() ви вказуєте ті дії, які повинні бути виконані перед знищенням об'єкта.

У загальному вигляді метод finalize() виглядає так:

Protected void finalize() (// тут фіналізація коду)

Тут ключове слово protected представляє специфікатор, що запобігає доступу finalize() за допомогою коду, що визначається поза його класом.

Це свідчить про те, що ви не можете знати як або навіть коли виконуватиметься finalize(). Наприклад, якщо ваша програма буде закінчена до «складання сміття», finalize() не виконуватиметься.

Конструктор - це спеціальний метод, який викликається під час створення нового об'єкта. Не завжди зручно ініціалізувати всі змінні класи під час створення його екземпляра. Іноді простіше, щоб якісь значення були створені за умовчанням під час створення об'єкта. Насправді конструктор необхідний автоматичної ініціалізації змінних.

Конструктор ініціалізує об'єкт безпосередньо під час створення. Ім'я конструктора збігається з ім'ям класу, включаючи регістр, а за синтаксисом конструктор схожий на метод без значення, що повертається.

Private int Cat(); // Так виглядає метод на ім'я Cat Cat(); // так виглядає конструктор класу Cat

На відміну від методу конструктор ніколи нічого не повертає.

Конструктор визначає дії, які виконуються під час створення об'єкта класу, і є важливою частиною класу. Як правило, програмісти намагаються явно зазначити конструктор. Якщо явного конструктора немає, Java автоматично створить його для використання за замовчуванням. Коли ми реалізовували клас Box, то жодного конструктора не створювали.

Додамо до класу конструктор, який просто встановить початкові значення для коробки.

Class Box ( int width; // ширина коробки int height; // висота коробки int depth; // глибина коробки // Конструктор Box() ( width = 10; height = 10; depth = 10; ) // обчислюємо обсяг коробки int getVolume() ( return width * height * depth; ) )

Ми тимчасово видалили метод setDim()та додали конструктор. Подивимось що вийде:

Box catBox = новий Box(); mInfoTextView.setText("Обсяг коробки: " + catBox.getVolume());

Програма виведе об'єм коробки, хоча ми не ставили жодних розмірів для неї. Завдяки конструктору будь-яка коробка, що створюється, матиме якийсь зафіксований обсяг.

Природно, ви можете повернути метод назад setDim()(див. статтю про класи) та встановити свої розміри для коробки:

Box catBox = новий Box(); // Встановимо свої розміри для коробки catBox.setDim (10, 20, 30); mInfoTextView.setText("Обсяг коробки: " + catBox.getVolume());

Тепер вам повинно бути ясно, що коли після ключового слова newми пишемо ім'я класу зі дужками, то насправді ми викликаємо конструктор класу.

Виникає питання - але спочатку при створенні класу ми не створювали конструктор, однак код new Box()працював. Справа в тому, що якщо конструктор не визначений явно, Java створить конструктор, який буде використовуватися за умовчанням. У цьому випадку він просто надасть усім змінним нульові значення. Якщо ви створили самі конструктор, то конструктор за замовчуванням не використовуватиметься.

Подібно до будь-якого методу, у конструктора можуть бути аргументи. У аргументах конструктора передаються параметри ініціалізації об'єкта. Наприклад, якщо у класу Catє конструктор, який отримує як аргумент ціле число, що означає вік кота, то об'єкти Catбудуть створюватися наступним чином:

Cat cat = новий Cat(8); // Коту 8 років

Якщо Cat(int)є єдиним конструктором класу, то компілятор не дозволить створювати об'єкти Catбудь-яким іншим способом.

Однак повернемося до коробок для котів. Створений нами конструктор не дуже корисний, тому що створює однакові коробки. Створимо конструктор із параметрами у класі Boxта закоментуйте перший конструктор без параметрів:

// Другий конструктор Box(int ​​w, int h, int d) (width = w; height = h; depth = d;)

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

// Це конструктор тепер не допустимо // Box catBox = new Box(); // У конструкторі необхідно вказати значення розмірів коробки Box catBox = new Box(100, 200, 100); mInfoTextView.setText("Обсяг коробки: " + catBox.getVolume());

До речі, з таким конструктором метод setDim()нам уже не потрібний. Ми можемо задати розміри коробки одразу в конструкторі. Так як швидше за все коробка стала і не змінює своїх розмірів, то метод, мабуть, зайвий. Але якщо ми змінюватимемо розміри коробки, то метод доведеться залишити.

Клас може мати кілька конструкторів. Зніміть коментар з першого конструктора та створіть дві коробки - коробку за замовчуванням та велику коробку.

Box defaultBox = новий Box(); mInfoTextView.setText("Обсяг стандартної коробки: " + defaultBox.getVolume()); Box bigBox = новий Box(100, 200, 200); mInfoTextView.append("\nОбсяг великої коробки: " + bigBox.getVolume());

Тобто ми бачимо, що конструктори підтримують навантаження, як і методи.

Наприклад, ми можемо створити ще один конструктор спеціально для коробки у вигляді куба, де всі сторони рівні:

// Третій конструктор для куба Box(int ​​len) (width = height = depth = len; )

Обчислюємо розмір куба:

Box cube = новий Box(5); int vol = cube.getVolume(); mInfoTextView.setText("Обсяг куба:" + vol);

Використовуємо об'єкт як параметри

Ми поки що використовували як параметри в конструкторах прості типи. Але можна передати об'єкт самого класу. Додамо ще один конструктор:

// Використовуємо об'єкт типу Box Box(Box ob) (width = ob.width; height = ob.height; depth = ob.depth; )

У коді програми можна скористатися конструктором так:

Box box1 = new Box(100, 200, 100); Box cloneBox = новий Box(box1); int vol = cloneBox.getVolume(); mInfoTextView.setText("Обсяг коробки:" + vol);

Клас Box (вихідник)

package ru.alexanderklimov.box; class Box ( int width; // ширина коробки int height; // висота коробки int depth; // глибина коробки // Конструктор Box() ( width = 10; height = 10; depth = 10; ) // Другий конструктор Box( int w, int h, int d) (width = w; height = h; depth = d;) // Третій конструктор для куба Box(int ​​len) (width = height = depth = len;) // Використовуємо об'єкт типу Box Box(Box ob) (width = ob.width; height = ob.height; depth = ob.depth; ) // обчислюємо обсяг коробки int getVolume() ( return width * height * depth; ) // встановлюємо розміри коробки void setDim (int w, int h, int d) ( width = w; height = h; depth = d; ) )

Виклик перевантажених конструкторів через this()

Маючи справу з перевантаженими конструкторами, зручно один конструктор викликати з іншого через ключове слово this. При виконанні конструктора this()спочатку виконується перевантажений конструктор, який відповідає списку параметрів. Потім виконуються оператори, що усередині вихідного конструктора, якщо такі існують. Виклик конструктора this()має бути першим оператором у конструкторі.

Для початку створимо клас, який не використовує конструктор this(), щоб зрозуміти різницю.

Class Cat (int age; int birthday; // Ініціалізуємо змінні явно Cat(int i, int j) (age = i; birthday = j;) // Ініціалізуємо змінні одним і тим значенням Cat(int i) (age = i; birthday = i; ) // Привласним значення за замовчуванням 0 Cat() ( age = 0; birthday = 0; ) )

Ми створили клас із трьома конструкторами. Перепишемо клас, використовуючи конструктор this().

Class Cat(int age; int birthday; // Ініціалізуємо змінні явно Cat(int i, int j) (age = i; birthday = j;) // Ініціалізуємо змінні одним і тим значенням Cat(int i) (this(i, i);// викликається Cat(i, i);

У нас тепер лише один конструктор, який надає значення полям – Cat(int, int). Що відбувається під час виконання оператора:

Cat cat = новий Cat(8);

Виклик конструктора Cat(8)призводить до виконання конструктора this(8, 8)що рівнозначно виклику конструктора Cat(8, 8).

Що відбувається під час виконання оператора:

Cat cat2 = новий Cat();

У цьому випадку викликається конструктор this(0)що призводить до виконання конструктора Cat(0)оскільки саме ця версія конструктора підходить за списком параметрів. При цьому конструктор Cat(0)по суті викликає конструктор Cat(0, 0).

Використання перевантажених конструкторів через конструктор this()дозволяє виключити дублювання коду, зменшуючи час завантаження класів.

Але слід бути обережним, оскільки конструктори, які викликають конструктор this(), Виконуються трохи повільніше.

Закритий конструктор

Іноді клас створюється лише зберігання якихось статичних полів і статичних методів. Таким класам прийнято давати імена Utilsале це не обов'язково. Такому класу не потрібен конструктор, але якщо автор класу його не створив, система сама створить конструктор за замовчуванням. Такий конструктор не має сенсу, а також може стати джерелом помилок. Щоб запобігти подібній проблемі ви самі явно повинні створити пустий конструктор і зробити його закритим.

Public class Utils ( private Utils() ( throw new AssertionError(); ) ... //Ваш правильний код // Неправильний код, тільки для демонстрації! toString(); ) )

Рядок throw new AssertionError()не є обов'язковою, але вона допоможе виявити помилку, якщо ви викличете конструктор у самому класі. Компілятор пропустить такий варіант, але програма завершиться помилково.

Utils.someMethod(); // програма закриється з помилкою

Підклас для цього класу ви створити не зможете.

Справа в тому що:

1. Якщо Ви створюєте клас і в ньому визначаєте конструктор з аргументами (клас AClass, який має лише один конструктор, який приймає int i), то компілятор вже не створить конструктор за замовчуванням. Тому що це порушило б контракт класу AClass, який може бути ініціалізований без аргументів. Якщо Ви хочете ще мати і конструктор за умовчанням, ставте тепер його явно.

Інакше не можна було заборонити створення конструктора за умовчанням, що було погано.

2. При створенні конструкторів класу BClass, який успадковується від іншого класу, компілятор вимагає, щоб першим рядком конструктора був виклик іншого конструктора (успадкованого або у цьому класі).

Чому? Тому що раз Ви успадкуєте від якогось класу, Ви хочете повторно використовувати його логіку. Конструктор наводить екземпляр класу в якийсь початковий цілісний стан. У Вашому випадку для ініціалізації AClass вимагає аргументу, без якого JVM не знає, як ініціалізувати екземпляр класу.

Якщо класу не визначено конструктори, він намагається створити конструктор за умовчанням, тобто. без аргументів:

Public class AClass1 ( )

Оскільки тут явно конструктори не визначені, І клас не успадковується від інших класів, компілятор створює конструктор за замовчуванням.

Це еквівалентно такому визначенню:

Public class AClass1 ( public AClass1() ( ) )

Тепер подивимося на BClass1:

Public class BClass1 extends AClass1 ( )

Тут також явно конструктори не визначені, і компілятор намагається створити конструктор за замовчуванням. Оскільки в класі AClass1 є конструктор за замовчуванням, він створить конструктор за замовчуванням, який викликатиме конструктор AClass1. Цей код еквівалентний такому:

Public class BClass1 extends AClass1 ( public BClass1() ( super(); ) )

У Вашому випадку створюється клас БЕЗ конструктора за замовчуванням:

Public AClass ( public AClass(int i) ( ) )

Оскільки тут описаний (хоч би один) конструктор, конструктор за умовчанням не створюється. Т. е. такий код вже не буде компілюватися:

AClass a = new AClass(); // не працює

потрібно щось на зразок

AClass a = new AClass(1);

Відповідно, будь-який конструктор BClass вимагатиме виклику будь-якого конструктора AClass або BClass. При такому описі компілятор лаятиметься:

Public BClass extends AClass ( )

Тому що буде спроба виклику конструкора за умовчанням класу AClass, який не визначено:

Public BClass extends AClass ( public BClass() ( super(); // помилка; в класі AClass немає такого конструктора ) )

Тим не менш, можна створити клас BClass з конструктором за замовчуванням, задавши якесь значення для конструктора AClass:

Public class BClass extends AClass ( public BClass() ( super(1); ) )

Це компілюватиметься.

Вітання! Сьогодні ми розберемо дуже важливу тему щодо наших об'єктів. Тут без перебільшення можна сказати, що цими знаннями ти користуватимешся щодня у реальній роботі! Ми поговоримо про конструкторах.

Ти, можливо, чуєш цей термін уперше, але насправді, напевно, користувався конструкторами, тільки сам не помічав цього:) Ми переконаємося в цьому пізніше.

Що таке конструктори та навіщо вони потрібні?

Розглянемо два приклади. public class Car (String model; для нього модель та максимальну швидкість. Однак у реальному проекті об'єкт Car явно матиме не 2 поля. А, наприклад, 16 полів! public class Car (String model; //модель int maxSpeed; //максимальна швидкість//об'єм двигуна//прізвище власника//кількість місць у салоні String salonMaterial; //матеріал салону boolean insurance; // Чи застрахована//країна виробник int trunkVolume; //обсяг багажника int accelerationTo100km; public static void main (String args) ( Car bugatti = new Car () ; bugatti. color = "blue" ; bugatti. accelerationTo100km = 3 ; bugatti. engineVolume = 6.3 ; bugatti. manufacturerCountry = "Italy" ; bugatti. Amigo" ; bugatti. yearOfIssue = 2016 ; bugatti. insurance = true ; bugatti. price = 2000000 ; bugatti. isNew = false ; bugatti. placesInTheSalon = 2 ; bugatti. Ми створили новий об'єкт Car. Одна проблема: полів у нас 16, а проініціалізували ми лише 12! Спробуй за кодом знайти ті, які ми забули! Не так просто, так? У такій ситуації програміст може легко помилитися та пропустити ініціалізацію якогось поля. У результаті поведінка програми стане помилковою: public class Car (String model; // модель int maxSpeed; //максимальна швидкість int wheels; //ширина дисків double engineVolume; //об'єм двигуна String color; //Колір int yearOfIssue; // Рік випуску String ownerFirstName; //ім'я власника String ownerLastName; //прізвище власника long price; //Ціна boolean isNew; //Нова чи ні int placesInTheSalon; //кількість місць у салоні String salonMaterial; //матеріал салону boolean insurance; // Чи застрахована String manufacturerCountry; //країна виробник int trunkVolume; //обсяг багажника int accelerationTo100km; //розгін до 100 км/год на секундах public static void main (String args) ( Car bugatti = new Car () ; bugatti. color = "blue" ; bugatti. accelerationTo100km = 3 ; bugatti. engineVolume = 6.3 ; bugatti. manufacturerCountry = "Italy" ; bugatti. Amigo" ; bugatti. yearOfIssue = 2016 ; bugatti. insurance = true ; bugatti. price = 2000000 ; bugatti. isNew = false ; bugatti. placesInTheSalon = 2 ; bugatti. out.println ( "Модель Bugatti Veyron. Об'єм двигуна - "+ Bugatti. engineVolume+", багажника -"+bugatti. trunkVolume + ", салон зроблений з "+ Bugatti. salonMaterial + ", ширина дисків -"+ Bugatti. wheels + ". Була придбана у 2018 році паном"+ Bugatti. ownerLastName) ; ) ) Виведення в консоль: Модель Bugatti Veyron. Об'єм двигуна - 6.3, багажника - 0, салон зроблений з null, ширина дисків - 0. Була придбана у 2018 році паном nullВашому покупцю, який віддав 2 мільйони доларів за машину, явно не сподобається, що його назвали “ паном null”! А якщо серйозно, у результаті в нашій програмі виявився некоректно створений об'єкт - машина із шириною дисків 0 (тобто взагалі без дисків), відсутнім багажником, салоном, зробленим з невідомого матеріалу, та ще й комусь, що належить незрозуміло. Можна тільки уявити, як така помилка може "вистрілити" під час роботи програми! Нам треба якось уникнути таких ситуацій. Треба щоб у нашій програмі було обмеження: при створенні нового об'єкта машини для нього завждиповинні бути вказані, наприклад, модель та максимальна швидкість. Інакше – не дозволяти створення об'єкта. З цим завданням легко справляються функції-конструктори. Вони одержали свою назву не просто так. Конструктор створює своєрідний "каркас" класу, якому кожен новий об'єкт класу має відповідати. Давай для зручності повернемося до простішого варіанту класу Car з двома полями. З урахуванням наших вимог, конструктор для класу Car буде виглядати так: public Car (String model, int maxSpeed) (this. model = model; this. maxSpeed ​​= maxSpeed;) А створення об'єкта тепер виглядає так: public static void main (String args ) ( Car bugatti = new Car ( " Bugatti Veyron " , 407 ) ; ) Зверніть увагу, як створюється конструктор. Він схожий на звичайний метод, але у нього немає типу значення, що повертається. При цьому в конструкторі вказується назва класу, також з великої літери. У нашому випадку - Car. Крім того, у конструкторі використовується нове для тебе ключове слово this. "this" по-англійськи - "цей, цього". Це слово свідчить про конкретний предмет. Код у конструкторі: public Car (String model, int maxSpeed) (this. model = model; this. конструктора. maxSpeed ​​для цієї машини (яку ми створюємо) = аргументу maxSpeed ​​, який вказаний у конструкторі." Так і сталося: public class Car (String model; int maxSpeed; public Car (String model, int maxSpeed) (this. model = model; this. Car ( " Bugatti Veyron " , 407 ) ; System. out. println (bugatti. model) ; System. Bugatti Veyron 407Конструктор успішно надав потрібні значення. Ти, мабуть, помітив, що конструктор дуже схожий на звичайний метод! Так воно і є: конструктор - це метод, тільки трохи специфічний:) Так само як у метод, наш конструктор ми передали параметри. І так само як виклик методу, виклик конструктора не спрацює, якщо їх не вказати: public class Car (String model; int maxSpeed; Public static void main (String args) (Car bugatti = new Car(); //помилка!)) Бачиш, конструктор зробив те, чого ми намагалися досягти. Тепер не можна створити машину без швидкості чи моделі! На цьому подібність конструкторів та методів не закінчується. Так само, як і методи, конструктори можна перевантажувати. Уяви, що в тебе вдома живуть 2 коти. Одного з них ти взяв кошеням, а другого ти приніс додому з вулиці вже дорослим і не знаєш точно, скільки йому років. Отже, наша програма має вміти створювати котів двох видів - з ім'ям та віком для першого кота, і лише з ім'ям - для другого кота. Для цього ми перевантажимо конструктор: public class Cat (String name; int age; //для першого кота //для другого кота Public Cat (String name) ( this . name = name; ) public static void main (String args) ( Cat barsik = новий Cat ( " Barsik " , 5 ) ; Cat street Спочатку конструктору з параметрами "ім'я" і "вік" ми додали ще один, тільки з ім'ям. Так само ми перевантажували методи в минулих уроках. Тепер ми успішно можемо створити обидва варіанти котів:)

Пам'ятаєш, на початку лекції ми говорили, що ти вже скористався конструкторами, тільки сам не помічав цього? Так і є. Справа в тому, що кожен клас Java має так званий конструктор за замовчуванням. У нього немає жодних аргументів, але він спрацьовує щоразу під час створення будь-якого об'єкта будь-якого класу. Public class Cat ( public static void main (String args) ( Cat barsik = new Cat () ; ) ) На перший погляд це непомітно. Ну, створили об'єкт і створили, де тут робота конструктора? Щоб це побачити, давай прямо руками напишемо для класу Cat порожній конструктор, а всередині нього виведемо якусь фразу в консоль. Якщо вона виведеться, то конструктор відпрацював. Public class Cat (public Cat () ( System. out. println ("Створили кота!") ; ) public static void main (String args) ( Cat barsik = new Cat () ; //Ось тут спрацював конструктор за замовчуванням } } Виведення в консоль: Створили кота! Ось і підтвердження! Конструктор за замовчуванням завжди незримо присутній у твоїх класах. Але тобі треба знати ще одну його особливість. Дефолтний конструктор зникає із класу, коли ти створюєш якийсь конструктор із аргументами.Доказ цього насправді ми вже бачили вище. Ось у цьому коді: public class Cat (String name; int age; public Cat (String name, int age) (this.name = name; this.age = age;)) new Cat () ; //помилка! ) ) Ми не змогли створити кота без імені та віку, тому що визначили конструктор для Cat: рядок + число. Дефолтний конструктор відразу після цього зникіз класу. Тому обов'язково запам'ятай: якщо тобі у твоєму класі потрібно кілька конструкторів, включаючи порожній, його потрібно створити окремо. Наприклад, ми створюємо програму для ветеринарної клініки. Наша клініка хоче робити добрі справи та допомагати бездомним котикам, про які ми не знаємо ні імені, ні віку. Тоді наш код має виглядати так: public class Cat (String name; int age; //для домашніх котів Public Cat (String name, int age) ( this . name = name; this . age = age; ) //для вуличних котів Public Cat () ( ) public static void main (String args) ( Cat barsik = новий Cat ( " Barsik " , 5 ) ; Cat streetCat = новий Cat () ; ) ) Тепер, коли ми явно прописали конструктор за замовчуванням, ми можемо створювати котів обох типів:) Для конструктора (як і будь-якого методу) дуже важливий порядок дотримання аргументів.Поміняємо у нашому конструкторі аргументи імені та віку місцями. Public class Cat (String name; int age; public Cat (int age, String name) ( this . name = name; this . age = age; ) public static void main (String args) ", 10); //помилка!)) Помилка! Конструктор чітко описує: при створенні об'єкта Cat йому мають бути передані число та рядок, саме в такому порядку. Тож наш код не спрацьовує. Обов'язково запам'ятай це та врахуй при створенні своїх власних класів: public Cat (String name, int age) (this. name = name; this. age = age;) public Cat (int age, String name) (this. age = age; this .name = name;) Це два абсолютно різних конструктора! Якщо висловити в одному реченні відповідь на запитання "Навіщо потрібен конструктор?", можна сказати: для того, щоб об'єкти завжди знаходилися у правильному стані. Коли ти використовуєш конструктори, всі твої змінні будуть коректно проініціалізовані, і в програмі не буде машин зі швидкістю 0 та інших неправильних об'єктів. Їхнє використання дуже вигідне насамперед для самого програміста. Якщо ти ініціалізуватимеш поля самостійно, великий ризик щось пропустити і помилитися. А з конструктором такого не буде: якщо ти передав у нього не всі потрібні аргументи або переплутав їх типи, компілятор одразу випустить помилку. Окремо варто сказати про те, що всередину конструктора не варто поміщати логіку твоєї програми. Для цього у твоєму розпорядженні є методи, В яких ти можеш описати весь потрібний тобі функціонал. Давай подивимося, чому логіка в конструкторі - це погана ідея: public class CarFactory (String name; int age; int carsCount; this.carsCount=carsCount;System.out.println( "Вона була заснована" "У середньому вона виробляє"+ (this . carsCount / this . age) + " машин на рік " ) ; ) public static void main ( String args ) ( CarFactory ford = new CarFactory, що описує фабрику виробництва автомобілів. Усередині конструктора ми ініціалізуємо всі поля, і сюди поміщаємо логіку: виводимо в консоль деяку інформацію про фабрику. Здавалося б - нічого поганого в цьому немає, програма чудово відпрацювала. Виведення в консоль: Наша автомобільна фабрика називається Ford Вона була заснована 115 років тому. За цей час на ній було вироблено 50000000 автомобілів. У середньому вона виробляє 434782 машин на рікАле насправді ми заклали міну уповільненої дії. І такий код може дуже легко призвести до помилок. Уявімо, що тепер ми говоримо що не про Ford, а про нову фабрику "Amigo Motors", яка існує менше року і виробила 1000 машин: public class CarFactory (String name; int age; age, int carsCount) (this. name = name; this. age = age; this. carsCount = carsCount; System. out. println ( "Наша автомобільна фабрика називається"+ this . name); System. out. println ( "Вона була заснована"+ this . age + "років тому"); System. out. println ( "За цей час на ній було зроблено"+ this . carsCount + "автомобілів"); System. out. println ( "У середньому вона виробляє"+ (this . carsCount / this . age) + " машин на рік " ) ; ) public static void main (String args) (CarFactory ford = new CarFactory ("Amigo Motors", 0, 1000);))) Наша автомобільна фабрика називається Amigo Motors Exception in thread "main" java.lang.ArithmeticException: / by zero Вона була заснована 0 років тому За цей час на ній було вироблено 1000 автомобілів у CarFactory. (CarFactory.java:15) at CarFactory.main(CarFactory.java:23) Process finished with exit code 1Приїхали! Програма завершилася з якоюсь незрозумілою помилкою. Спробуєш здогадатися, у чому причина? Причина – у логіці, яку ми помістили у конструктор. А саме - ось у цьому рядку: System. out. println ( "У середньому вона виробляє"+ (this . carsCount / this . age) + " машин на рік " ) ; Тут ми виконуємо обчислення та ділимо кількість вироблених машин на вік фабрики. А оскільки наша фабрика нова (тобто їй 0 років) – у результаті виходить розподіл на 0, який у математиці заборонено. В результаті програма завершується помилково. Як же нам варто було вчинити?Винести всю логіку в окремий метод і назвати його, наприклад, printFactoryInfo() . Як параметр йому можна передати об'єкт CarFactory. Туди ж можна помістити всю логіку, і заразом - обробку можливих помилок, на зразок нашої з нулем років. Кожному своє. Конструктори необхідні коректного завдання стану об'єкта.Для бізнес-логіки ми маємо методи. Не варто змішувати одне з одним. Ось кілька корисних посилань, де ти можеш додатково почитати про конструкторів:



Сподобалася стаття? Поділіться їй