JavaRush /Курсы /Модуль 1. Java Syntax /Жизненный цикл объекта

Жизненный цикл объекта

Модуль 1. Java Syntax
15 уровень , 1 лекция
Открыта
Привет! Жизненный цикл объекта  - 1Думаю, ты не сильно удивишься, если тебе сказать, что размер памяти на твоем компьютере ограничен:) Даже жесткий диск, который в разы больше оперативной памяти, можно забить под завязку любимыми играми, сериалами и прочим. Чтобы этого не произошло, нужно следить за текущим состоянием памяти и удалять с компа ненужные файлы. Какое отношение ко всему этому имеет программирование на Java? Прямое! Ведь при создании любого объекта Java-машиной под него выделяется память. В реальной большой программе создаются десятки и сотни тысяч объектов, под каждый из которых в памяти выделяется свой кусочек. Но как ты думаешь, сколько существуют все эти объекты? “Живут” ли они все время, пока работает наша программа? Разумеется, нет. При всех достоинствах Java-объектов, они не бессмертны :) У объектов есть собственный жизненный цикл. Сегодня мы чуть-чуть отдохнем от написания кода и рассмотрим этот процесс :) Тем более что он является очень важным для понимания работы программы и распоряжения ресурсами. Итак, с чего же начинается жизнь объекта? Как и у человека — с его рождения, то есть, создания.

Cat cat = new Cat();//вот сейчас и начался жизненный цикл нашего объекта Cat!
Вначале виртуальная Java-машина выделяет необходимый объем памяти для создания объекта. Потом она создает на него ссылку, в нашем случае — cat, чтобы иметь возможность его отслеживать. После этого происходит инициализация всех переменных, вызов конструктора и вот — наш свежий объект уже живет своей жизнью :) Срок жизни у объектов разный, точных цифр здесь не существует. В любом случае, в течение какого-то времени он живет внутри программы и выполняет свои функции. Если говорить точно, объект является “живым” пока на него есть ссылки. Как только ссылок не остается — объект “умирает”. Например:

public class Car {
  
   String model;

   public Car(String model) {
       this.model = model;
   }

   public static void main(String[] args) {
       Car lamborghini  = new Car("Lamborghini Diablo");
       lamborghini = null;

   }

}
В методе main() объект машины Lamborghini Diablo перестает быть живым уже на второй строке. На него была всего одна ссылка, а теперь этой ссылке был присвоен null. Поскольку на Lamborghini Diablo не осталось ссылок, он становится “мусором”. Ссылку при этом не обязательно обнулять:

public class Car {

   String model;

   public Car(String model) {
       this.model = model;
   }

   public static void main(String[] args) {
       Car lamborghini  = new Car("Lamborghini Diablo");

       Car lamborghiniGallardo = new Car("Lamborghini Gallardo");
       lamborghini = lamborghiniGallardo;
   }

}
Здесь мы создали второй объект, после чего взяли ссылку lamborghini и присвоили ей этот новый объект. Теперь на объект Lamborghini Gallardo указывает две ссылки, а на объект Lamborghini Diablo — ни одной. Поэтому объект Diablo становится мусором. И в этот момент в работу вступает встроенный механизм Java под названием сборщик мусора, или по-другому — Garbage Collector, GC.
Жизненный цикл объекта  - 2
Сборщик мусора — внутренний механизм Java, который отвечает за освобождение памяти, то есть удаление из нее ненужных объектов. Мы не зря выбрали для его изображения картинку с роботом-пылесосом. Ведь сборщик мусора работает примерно так же: в фоновом режиме он “ездит” по твоей программе, собирает мусор, и при этом ты с ним практически не взаимодействуешь. Его работа — удалять объекты, которые уже не используются в программе. Таким образом он освобождает в компьютере память для других объектов. Помнишь в начале лекции мы говорили, что в обычной жизни тебе приходится следить за состоянием твоего компьютера и удалять старые файлы? Так вот, в случае с Java-объектами сборщик мусора делает это вместо тебя. Garbage Collector запускается многократно в течение работы твоей программы: его не надо вызывать специально и отдавать команды, хотя технически это возможно. Позднее мы еще поговорим о нем и разберем процесс его работы более детально. В момент, когда сборщик мусора добрался до объекта, перед самым его уничтожением, у объекта вызывается специальный метод — finalize(). Его можно использовать, чтобы освободить какие-то дополнительные ресурсы, которые использовал объект. Метод finalize() принадлежит классу Object. То есть, наравне с equals(), hashCode() и toString(), с которыми ты уже познакомился ранее, он есть у любого объекта. Его отличие от других методов в том, что он... как бы это сказать... весьма своенравен. А именно — перед уничтожением объекта он вызывается далеко не всегда. Программирование — штука точная. Программист говорит компьютеру что-то сделать — компьютер это и делает. Ты, полагаю, уже привык к такому поведению, и тебе поначалу может быть сложно принять идею: “Перед уничтожением объектов вызывается метод finalize() класса Object. Или не вызывается. Как повезет!” Тем не менее, это действительно так. Java-машина сама определяет, вызывать метод finalize() в каждом конкретном случае или нет. Например, давай попробуем ради эксперимента запустить такой код:

public class Cat {

   private String name;

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

   public Cat() {
   }

   public static void main(String[] args) throws Throwable {
       for (int i = 0 ; i < 1000000; i++) {
           Cat cat = new Cat();
           cat = null;//вот здесь первый объект становится доступен сборщику мусора
       }
   }

   @Override
   protected void finalize() throws Throwable {
       System.out.println("Объект Cat уничтожен!");
   }
}
Мы создаем объект Cat и уже в следующей строчке кода обнуляем единственную ссылку на него. И так — миллион раз. Мы явно переопределили метод finalize(), и он должен миллион раз вывести строку в консоль, каждый раз перед уничтожением объекта Cat. Но нет! Если быть точным, на моем компьютере он отработал всего 37346 раз! То есть только в 1 случае из 27-ми установленная у меня Java-машина принимала решение вызвать метод finalize() — в остальных случаях сборка мусора проходила без этого. Попробуй запустить этот код у себя: скорее всего, результат будет отличаться. Как видишь, finalize() трудно назвать надежным партнером :) Поэтому небольшой совет на будущее: не стоит полагаться на метод finalize() в случае с освобождением каких-то критически важных ресурсов. Может JVM его вызовет, а может нет. Кто знает? Если твой объект при жизни занимал какие-то суперважные для производительности ресурсы, например, держал открытым соединение с базой данных, лучше создай в своем классе специальный метод для их освобождения и вызови его явно, когда объект уже будет не нужен. Так ты точно будешь знать, что производительность твоей программы не пострадает. В самом начале мы сказали, что работа с памятью и удаление мусора очень важны, и это действительно так. Неподобающая работа с ресурсами и непонимание процесса сборки ненужных объектов могут привести к утечке памяти. Это одна из самых известных ошибок в программировании. Неправильно написанный программистом код может привести к тому, что для вновь созданных объектов каждый раз будет выделяться новая память, при этом старые, ненужные объекты будут недоступны для удаления сборщиком мусора. Раз уж мы привели аналогию с роботом пылесосом, представь, что будет, если перед запуском робота разбросать по дому носки, разбить стеклянную вазу и оставить на полу разобранный конструктор Lego. Робот, конечно, попытается что-то сделать, но в один прекрасный момент он застрянет.
Жизненный цикл объекта  - 3
Для его правильной работы нужно держать пол в нормальном состоянии и убирать оттуда все, с чем не справится пылесос. По такому же принципу работает и сборщик мусора. Если в программе будет оставаться много объектов, которые он не может собрать (как носок или Lego для робота-пылесоса), в один прекрасный момент память закончится. И может зависнуть не только написанная тобой программа, но и все остальные программы, запущенные в этот момент на компьютере. Для них тоже может не хватать памяти.

Это не нужно заучивать: достаточно просто понять принцип работы.

15
Задача
Java Syntax Pro, 15 уровень, 1 лекция
Недоступна
Поработай обработчиком
Для начала разберись, что делает программа, а затем: 1. В методе addUser обработай значение, возвращаемое методом setName: - если setName вернул -1, выведи сообщение: "Имя не может быть null." - если -2, выведи сообщение: "Имя не может быть пустым." - если -3, выведи сообщение: "Имя не может содер
Комментарии (13)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Руслан Уровень 111 Expert
17 января 2025
класс собака extends от волка?? а не наоборот ли?)
Руслан Никитин Уровень 109
29 мая 2024
тем временем метод устарел уже до

@Deprecated(since="9")
    protected void finalize() throws Throwable { }
}
Павел Уровень 19 Expert
6 августа 2023
Решил повторить с небольшими изменениями код с созданием и последующим уничтожением объекта для наблюдением за сборщиком мусора. Использовал такой способ

public static void main(String[] args) throws Throwable {
        for (int i = 0 ; i < 1000000; i++) {
            Cat cat = new Cat();
            cat = null;//вот здесь первый объект становится доступен сборщику мусора
        }
        System.out.println(count);
    }
@Override
    protected void finalize() throws Throwable {
        count++;
        System.out.println("Объект Cat уничтожен! count=" + count);
    }
count - статическая переменная счетчик После выполнения finalize() внутри цикла получил вывод count. Но на этом выполнение finalize() не прекратилось. Было еще около 500 вызовов finalize() вне цикла создания и уничтожения объекта Cat.
Акынбек Уровень 77 Expert
24 апреля 2023
мы не обязаны знать заранее про Волка и Собаку 🤬
Дмитрий Саргаев Уровень 76 Expert
25 августа 2022
9 вопрос не однозначно поставлен) Это тоже самое, что спросить Mers extends BMW or BMW extends Mers) Очевидно, что собака ничем не отличается по свойствам от волка. Они живут в разных местах, но это некорректно представлять как наследование. Ходит собака на 4 лапах, также лает и воет, ест мясо и водится стаями в подворотнях. В чем наследование, Карл? :)
Никита Уровень 27
10 сентября 2024
Ну, если смотреть в жизни, то собаки произошли от волков, нельзя сказать, что волки произошли от собак.
Сергей Уровень 111 Expert
18 мая 2022

В каком из вариантов правильно описано наследование класса Собака и класса Волк?
Вопрос так вопрос, что появилось раньше: яйцо или курица....
java Уровень 108 Expert
12 сентября 2022
Ну вероятнее волк появился раньше, это же еще со школы все знают😅а насчет курицы, скорее всего первым появилось яйцо какого нибудь динозавра, а потом в результате мутаций из яйца динозавра каким то образом получился первый цыпленок, или что-то, что в последствии в результате мутаций стало цыплёнком
Олег Уровень 26
15 сентября 2022
волк - отряд хищных млекопитающих из семейства псовых... Значит по идее должно быть правильно собака - класс-родитель, а не наоборот как в правильном ответе
java Уровень 108 Expert
15 сентября 2022
Есть ясные свидетельства, что собаки произошли именно от серых волков на начальном этапе одомашнивания и никакие другие дикие виды псовых в это не были вовлечены. Если бы там был класс семейство псовых, то тогда да он родитель для класса волк, но именно для собаки родитель волк
Pixta Уровень 108 Expert
31 декабря 2021
Если класс не унаследован ни от кого, то он.... рассмешили ответы на вопрос))
Владимир Уровень 109 Expert
23 февраля 2022
Бездомный 🤣🤣🤣
Виктор Шефф Уровень 111 Expert
16 декабря 2021

        @Override
        protected void finalize() throws Throwable {
               System.out.println("Объект Cat уничтожен!");
        }