JavaRush /Курсы /Java Syntax Pro /Инициализация

Инициализация

Java Syntax Pro
11 уровень , 3 лекция
Открыта

1. Инициализация переменных

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

Однако эти же переменные можно инициализировать и в конструкторе. Поэтому теоретически возможна ситуация, когда одним и тем же переменным класса значения присваиваются дважды. Пример

Код Примечание
class Cat
{
   public String name;
   public int age = -1;

   public Cat(String name, int age)
   {
     this.name = name;
     this.age = age;
   }

   public Cat()
   {
     this.name = "Безымянный";
   }
}



Переменной age присваивается стартовое значение




Стартовое значение перетирается


Для age используется стартовое значение
 Cat cat = new Cat("Васька", 2);
Так можно: вызовется первый конструктор
 Cat cat = new Cat();
Так можно: вызовется второй конструктор

Вот что будет происходить при выполнении кода Cat cat = new Cat("Васька", 2);:

  • Создается объект типа Cat
  • Инициализируются все переменные класса своими стартовыми значениями
  • Вызывается конструктор и выполняется его код.

Т.е. переменные класса сначала инициализируются своими значениями, а уже затем выполняется код конструкторов.


2. Порядок инициализации переменных класса

Переменные не просто инициализируются до работы конструктора: они еще и инициализируются в четко заданном порядке — порядке объявления в классе.

Давайте рассмотрим такой интересный код:

Код Примечание
public class Solution
{
   public int a = b + c + 1;
   public int b = a + c + 2;
   public int c = a + b + 3;
}

Такой код не скомпилируется, т.к. на момент создания переменной а, переменных b и c еще нет. А вот так записать можно, и этот код отлично скомпилируется и будет работать.

Код Примечание
public class Solution
{
   public int a;
   public int b = a + 2;
   public int c = a + b + 3;
}


0
0+2
0+2+3

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

Тут нужно помнить, что все переменные класса до того, как им присвоили какое-либо значение, имеют значение по умолчанию. Для типа int это ноль.

Когда JVM будет инициализировать переменную а, просто присвоит ей значение по умолчанию для типа int — 0.

Когда очередь дойдет до b, переменная a уже будет известна и содержать значение, поэтому JVM присвоит ей значение 2.

Ну а когда дело дойдет до переменной c, переменные а и b уже будет проинициализированы, и JVM легко вычислит стартовое значение для с: 0+2+3.

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


3. Константы

Раз уж мы продолжаем разбирать процесс создания объекта, стоит затронуть вопрос инициализации констант — переменных класса, которые имеют модификатор final.

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

Но вот чего вы не знаете, так это того, что стартовое значение можно сразу не присваивать, если присвоить его в конструкторе. И это отлично будет работать для final-переменной. Единственное требование — если конструкторов несколько, final переменной должно быть присвоено значение во всех конструкторах.

Пример:

public class Cat
{
   public final int maxAge = 25;
   public final int maxWeight;

   public Cat (int weight)
   {
      this.maxWeight = weight; // занесение стартового значения в константу
   }
}

11
Задача
Java Syntax Pro, 11 уровень, 3 лекция
Недоступна
Жажда скорости
Почувствуй себя автоконструктором и найди решение, как сделать так, чтобы завод снова заработал. Для этого тебе нужно добавить инициализацию полей в конструкторах соответствующими параметрами. Если параметр отсутствует, то нужно инициализировать поле значением по умолчанию. Для поля year это текущий

4. Код в конструкторе

И еще несколько важных замечаний насчет конструкторов. В будущем, в процессе изучения Java, вы столкнётесь с такими вещами как наследование, сериализация, исключения и т.п. Они все в разной степени влияют на работу конструкторов. Сейчас нет смысла сильно углубляться в эти темы, но хотя бы коснуться их мы как минимум обязаны.

Например, одно важное замечание насчет конструкторов. Теоретически в конструкторе можно писать код любой сложности. Но не нужно этого делать. Пример:

class FilePrinter
{
   public String content;

   public FilePrinter(String filename) throws Exception
   {
      FileInputStream input = new FileInputStream(filename);
      byte[] buffer = input.readAllBytes();
      this.content = new String(buffer);
   }

   public void printFile()
   {
      System.out.println(content);
   }
}






Открываем поток чтения файла
Читаем файл в массив байт
Сохраняем массив байт в виде строки




Выводим содержимое файла на экран

В конструкторе класса FilePrinter мы сразу открыли байтовый поток к файлу и прочитали его содержимое. Это достаточно сложное поведение, которое может потенциально привести к ошибкам.

А что если бы такого файла не было? А если бы были проблемы с его чтением? А если бы он был слишком большим?

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

Пример 1 – Сериализация

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

И вот тут окажется, что на другом компьютере нет вашего файла, в конструкторе возникнет ошибка, и никто ее не обработает — что вполне себе способно привести к закрытию программы.

Пример 2 — Инициализация полей класса

Если конструктор вашего класса может выбросить checked-исключения – содержит ключевое слово throws, вы обязаны перехватить это исключение в методе, который создает ваш объект.

А если такого метода нет? Пример:

Код  Примечание
class Solution
{
   public FilePrinter reader = new FilePrinter("c:\\readme.txt");
}
Такой код не скомпилируется.

Конструктор класса FilePrinter содержит checked-исключения: вы не можете создать объект FilePrinter, не обернув его в try-catch. А try-catch можно писать только в методе


11
Задача
Java Syntax Pro, 11 уровень, 3 лекция
Недоступна
Многосерийный предприниматель
Постройка здания планировалась под ресторан и успешно завершилась, но спустя некоторое время собственники решили переделать его под барбершоп. Нам нужно сделать так, чтобы здание было универсальным, и его назначение можно было менять, не создавая нового. Для этого создай метод initialize, который

5. Конструктор базового класса

В предыдущих лекциях мы немного обсуждали наследование. К сожалению, полностью наследование и ООП мы будем обсуждать на уровне, посвященном ООП, а конструкторов это касается уже сейчас.

Если вы унаследуете свой класс от другого класса, фактически в объект вашего класса будет встроен объект класса-родителя. Причем этот класс-родитель имеет свои переменные класса и свои конструкторы.

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

Классы

Как же нам узнать, в каком порядке инициализируются переменные и вызываются конструкторы? Давайте для начала напишем код двух классов, один из которых наследуется от другого:

Код Примечание
class ParentClass
{    public String a;
   public String b;

   public ParentClass()
   {
   }
}

class ChildClass extends ParentClass
{
   public String c;
   public String d;

   public ChildClass()
   {
   }
}










Класс ChildClass наследуется от класса ParentClass.

Нам нужно определить, в каком же порядке инициализируются переменные и вызываются конструкторы. Сделать это нам поможет логирование.

Логирование

Логированием называется запись в консоль или файл действий, которые происходят во время работы программы.

Определить, что вызвался конструктор, довольно просто: нужно в теле конструктора написать в консоль сообщение об этом. А вот как определить, что переменная инициализировалась?

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

Финальный код

public class Main
{
   public static void main(String[] args)
   {
      ChildClass obj = new ChildClass();
   }

   public static String print(String text)
   {
      System.out.println(text);
      return text;
   }
}

class ParentClass
{
   public String a = Main.print("ParentClass.a");
   public String b = Main.print("ParentClass.b");

   public ParentClass()
   {
      Main.print("ParentClass.constructor");
   }
}

class ChildClass extends ParentClass
{
   public String c = Main.print("ChildClass.c");
   public String d = Main.print("ChildClass.d");

   public ChildClass()
   {
      Main.print("ChildClass.constructor");
   }
}




Создаем объект типа ChildClass


Этот метод пишет в консоль переданный текст и возвращает его же





Объявляем ParentClass

Пишем текст и им же инициализируем переменные




Пишем в консоль сообщение о вызове конструктора. Возвращаемое значение игнорируем.


Объявляем ChildClass

Пишем текст и им же инициализируем переменные




Пишем в консоль сообщение о вызове конструктора. Возвращаемое значение игнорируем.

Если выполнить этот код, на экран выведется текст:

Вывод на экран метода Main.print()
ParentClass.a ParentClass.b ParentClass.constructor
ChildClass.c ChildClass.d ChildClass.constructor

Так что вы всегда лично можете убедиться, что переменные класса инициализируются до вызова его конструктора. Вся инициализация базового класса идет до инициализации класса-наследника.


11
Задача
Java Syntax Pro, 11 уровень, 3 лекция
Недоступна
Кто тут наследник?
Эта задача нужна для понимания того, как вызывается конструктор базового класса (родителя). У тебя есть классы ElectricCar, GasCar, HybridCar, которые наследуют класс Car. Тебе нужно в конструкторах наследников класса Car передать тип автомобиля в конструктор базового класса (родителя), использ
Комментарии (437)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
donz99 Уровень 13
8 июня 2025
Бился над последней задачей около часа, пока не нашёл этот комментарий, может кому-нибудь он тоже поможет: Решал задачу по super. Как итог понял, что:

Super("Параметр")
вызывает конструктор родителя с Параметром который я указал в Super. У меня конструктор родитель:

public Box(String material) {
        System.out.println("Коробка из материала " + material);  }
когда я в классе ребенке хочу вызвать родительский класс, то вызываю только

public Plastic() {
        super("Пластик");} // здесь указываю параметр как будто 
                           //использую конструктор public Box(String material).
и вывод на печать будет как у родителя, т.е. я использовал одну команду Super и вызвал целый конструктор в него. конечно создав в main конструктор

Мне помогло разобраться.
public static void main(String[] args) {
        Plastic plastic = new Plastic();}
Владимир Уровень 11
21 мая 2025
что я делаю не правильно? Есть класс Main, там public class CarConcern есть конструктор и прописаны константы. Хочу создать переменную с типом CarConcern, и вывести на экран константу. В идее выдаёт ошибку: java: non-static variable this cannot be referenced from a static context текст класса: public class Main { public class CarConcern { private final String manufacturer = "Lamborghini"; private final String model; private final int year; private final String color; public CarConcern() { //напишите тут ваш код model=""; year=4321; color="Оранжевый"; System.out.println(color+" "+year); } } public static void main(String[] args) { CarConcern carConcern =new CarConcern(); } }
Anastasia Panferova Уровень 11
22 мая 2025
в статическом методе main нельзя напрямую создать объект нестатического внутреннего класса
Владимир Уровень 11
24 мая 2025
А как не напрямую?
Владимир Уровень 11
24 мая 2025
Всё получилось, спасибо)) public class Main { private final String manufacturer = "Lamborghini"; private final String model; private final int year; private final String color; public Main() { //напишите тут ваш код model=""; year=4321; color="Оранжевый"; System.out.println(color+" "+year); } public static void main(String[] args) { Main carConcern =new Main(); } } Вот код, он работает)
spector Уровень 11
20 мая 2025
время, потраченное на решение последней задачи, было проведено просто super("no");
Anonymous #3478746 Уровень 11
3 мая 2025
если допустим у конструктора родительского класса есть несколько параметров, как команда super("GasCar"); узнает какому параметру присвоить значение "GasCar" ? задачу я решил, но есть ощущение что я не доконца понял как это работает
Виктор Уровень 14
15 мая 2025
По очереди будет присваивать согласно очереди в конструкторе наверное.
Bilal Уровень 15
26 апреля 2025
Крайне рекомендую после этого урока сразу ознакомиться с доп статьей Конструкторы базовых классов
Сергей Уровень 14
13 апреля 2025
Дамы и господа, леди и джентльмены, прекратите))) задачка супер! никаких лишний лекций не надо! idea intellij Вам в помощь! не поленитесь, создайте 5 файликов, и придёт понимание)))
Искендер Уровень 27
11 апреля 2025
есть хорошее правило, не можешь сам - обратись к профессионалам. может надо обратиться джаварашу к методистам по разработке нормального обучения уже?
Жуков Богдан Уровень 26
30 марта 2025
Позорная лекция какая-то.. Частично про это либо было написано ранее, либо текст не связан с задачей (пятый пункт). Такое ощущение, что лекцию писал джун, который нахватал познаний из разных источников и решил вывалить все на читателя.. У вас структуру лекций и уровней вообще кто-то проверяет?
Danya Уровень 17
1 апреля 2025
хз как будто просто повторение пройденной темы вроде норм
Ilya_haha Уровень 13
26 марта 2025
Самая глупая и непонятная лекция, купи подписку, СИДИ и ГУГЛИ Часа 2 сидеть разбираться с тем, чего в лекции нету ЕЛЕ ЕЛЕ super() обьяснение! дадададада, мы должны уметь гуглить https://javarush.com/groups/posts/1187-raznica-mezhdu-kljuchevihmi-slovami-this-i-super-v-java (комменты оттуда помогли разобраться)
29 апреля 2025
"super() объяснение!" ахаххаха вообще в самую точку
arsvasimov Уровень 38
11 февраля 2025
Нормально так-то
rusvasimov Уровень 37
11 февраля 2025
Ну да, легко.