JavaRush /Курсы /Java Syntax Pro /Нюансы объектов в Java

Нюансы объектов в Java

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

1. Свойства: геттер и сеттер

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

Никто детально не изучает документацию по классам, или в ней могут быть не описаны все случаи, поэтому часто могут возникать ситуации, когда данные внутри объекта «портятся», и объект становится не валидным.

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

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

Код Примечание
class Person
{
   private String name;

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

   public String getName()
   {
      return name;
   }

   public void setName(String name)
   {
      this.name = name;
   }
}


private-поле name



Инициализация поля через конструктор


getName()— метод возвращает значение поля name




setName()— метод изменяет значение поля name

Никакой другой класс не сможет изменить значение поля name напрямую. Если кому-то нужно получить значение поля name, ему придется вызвать метод getName() у объекта типа Person. Если какой-то код хочет поменять значение поля name, ему нужно будет вызвать метод setName() у объекта типа Person.

Метод getName() еще называют «геттер поля name», а  метод setName() — «сеттер поля name».

Это очень распространённый подход. В 80-90% всего Java кода вы никогда не увидите публичные переменные класса. Вместо этого они будут объявлены private (ну или protected), и у каждой переменной будут публичные геттеры и сеттеры.

Этот подход делает код длиннее, но надежнее.

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

Допустим, вы хотите создать класс, который описывает точку на плоскости x и y. Вот как это сделал бы программист-новичок:

class Point
{
   public int x;
   public int y;
}

А вот как это бы сделал опытный Java-программист:

Код
class Point {
 private int x;
 private int y;

   public Point(int x, int y) {
      this.x = x;
      this.y = y;
   }

   public int getX() {
      return x;
   }

   public void setX(int x) {
      this.x = x;
   }

   public int getY() {
      return y;
   }

   public void setY(int y) {
      this.y = y;
   }
}

Код стал длиннее? Безусловно.

Зато в сеттеры и геттеры можно добавить валидацию параметров. Например, можно следить за тем, чтобы x и y всегда были больше нуля (или не меньше нуля). Пример:

Код Примечание
class Point {
   private int x;
   private int y;

   public Point(int x, int y) {
      this.x = x < 0 ? 0 : x;
      this.y = y < 0 ? 0 : y;
   }

   public int getX() {
      return x;
   }

   public void setX(int x) {
      this.x = x < 0 ?  0 : x;
   }

   public int getY() {
      return y;
   }

   public void setY(int y) {
      this.y = y < 0 ? 0 : y;
   }
}

11
Задача
Java Syntax Pro, 11 уровень, 4 лекция
Недоступна
С крышей или без? Вот в чем вопрос
Ты сделал предзаказ на новенькую Bugatti ровно полгода назад. Сейчас июнь, и было бы неплохо все-таки ездить на кабриолете. Но ты забыл, в каком кузове заказывал машину. Твоя задача — добавить функциональность для получения текущей конфигурации и изменения её при необходимости. Для этого создай гетт
11
Задача
Java Syntax Pro, 11 уровень, 4 лекция
Недоступна
Зарплата
У нас есть класс Programmer, в котором есть очень важное поле — salary. Наша задача следующая: нужно добавить возможность получить и изменить значение этого поля, используя геттер и сеттер. Но есть нюанс: зарплату можно только повышать. Поэтому тебе нужно добавить проверку в сеттер: если значение ар

2. Время жизни объекта

Вы уже знаете, что объекты создаются с помощью оператора new, а вот как объекты удаляются? Не существуют же они вечно — для этого никакой памяти не хватит.

Во многих языках программирования, таких как С++, для удаления объекта есть специальный оператор delete. А как ситуация с этим обстоит в Java?

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

В Java процесс удаления объектов полностью автоматизирован – удалением объектов занимается сама Java-машина. Такой процесс называется сборкой мусора (garbage collecting), а механизм, который собирает мусор — сборщиком мусораGarbage Collector или сокращенно GC.

Так как Java-машина узнает, что какой-то объект нужно удалить и когда?

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

В Java нельзя взять и создать ссылку на существующий объект: ее можно только присвоить. Если мы стерли все ссылки на объект, он утерян навсегда.

Циклические ссылки

Предыдущая логика звучит отлично, пока мы не придумаем простой контрпример: у нас есть два объекта, которые ссылаются друг на друга (хранят ссылки друг на друга). Больше никто никаких ссылок на эти объекты не хранит.

К этим объектам нельзя обратиться из остального кода, однако ссылки на них все же есть.

Именно поэтому сборщик мусора делит объекты не на «объекты со ссылками» и «объекты без ссылок», а на достижимые и недостижимые.

Достижимые объекты

Сначала в список достижимых добавляются те объекты, которые 100% живые. Например, текущий поток (Thread.current()) или Консоль (System.in).

Затем список достижимых объектов пополняют те, на которые ссылаются первые достижимые объекты. Затем те, на кого ссылаются вторые и т.д.

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


3. Сборка мусора

Фрагментация памяти

Еще один важный момент, связанный с удалением объектов — фрагментация памяти. Если постоянно создавать и удалять объекты, скоро вся память будет вперемешку: области занятой памяти будут постоянно перемежаться пустыми областями.

И легко может случиться ситуация, когда мы не можем создать большой объект (например, массив на миллион элементов), потому что нет большого куска свободной памяти. Т.е. свободная память вроде и есть, и много, но вот большого цельного куска свободной памяти может и не быть

Оптимизация (дефрагментация) памяти

Java-машина решает эту проблему специфическим образом. Выглядит это примерно так:

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

Выглядит этот процесс примерно так:

Этап 1: После создания объектов

Сборка мусора в Java

Этап 2: Появление «дыр»

Сборка мусора в Java

Этап 3: Устранение «дыр»

Сборка мусора в Java

Таким образом, даже не нужно удалять объекты. Java-машина просто копирует все достижимые объекты в новое место, а всю область памяти со старыми объектами объявляет свободной.

Комментарии (262)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Anonymous #3533104 Уровень 12
28 мая 2025
расскажите пожалуйста почему у нас сетер возвращает void
Ruslan Уровень 15
28 мая 2025
Основная задача сеттера - изменить значение поля класса, а не возвращать какой-либо результат. Если поменять тип на int вместо void, то IDE сразу заругается на отсутствие оператора return.
Anonymous #3533104 Уровень 12
29 мая 2025
аа окей
Danya Уровень 17
1 апреля 2025
Топовое обьяснение от GPT: Представь, что у тебя есть коробка (это будет наш объект), в которой ты хранишь свои игрушки (это будут поля). Ты хочешь, чтобы другие люди могли узнать, какие игрушки в коробке (это геттер), или положить туда новые игрушки (это сеттер). Но ты не хочешь, чтобы они могли просто взять коробку и без твоего разрешения поменять или вытащить игрушки. Геттер — это как ключик, который позволяет другим людям посмотреть, какие игрушки в коробке. Они могут открыть коробку и посмотреть, но не могут что-то там менять. Сеттер — это как ключик, который позволяет другим людям положить новые игрушки в коробку, но ты решаешь, какие именно игрушки можно положить, а какие нет. Например, если кто-то пытается положить игрушку, которая слишком большая, ты можешь сказать "нет, это не пройдет".
Anonymous #3533104 Уровень 12
28 мая 2025
блен ну это топчик
15 марта 2025
В GC различают области памяти: New generation, которая в свою очередь делится на: 1.1. Eden 1.2. S0 1.3. S1 Old generation. В New generation к вышеописанному происходит следующее: Все новые объекты попадают в Eden (иногда ее называют эдемом, но это неправильно, но лучше запоминается). Когда Eden заполняется и нет места, срабатывает сборщик мусора и по вышеописанному методу начинает все живые объекты перекидывать в S0. Таким образом Eden освобождается. И у нас пусто в Eden и S1. Дальше программа работает, и опять при заполнении Eden включается сборщик мусора (но у нас уже занято в S0). Все живые объекты, которые есть в Eden и S0, он перекладывает в S1 (при этом области памяти Eden в и S0 освобождаются). Дальше опять работает программа, и снова при аполнении Eden включается сборщик мусора (но у нас уже занято в S1). Тогда все живые объекты, которые есть в Eden и S1, он перекладывает в S0 (области памяти Eden в и S1 освобождаются). Таких циклов происходит вроде 15(необходимо уточнить) или пока область New generation не будет заполнена полностью. Тогда происходит кратковременная остановка памяти, и включается Major GC, и все живые объекты перекидываются в Old generation. Память New generation полностью освобождается, и программа начинает работать по описанию выше. Еще необходимо отметить, что GC включает: Пометку — на этом этапе идентифицируются объекты, которые не используются. Очистка — удаление идентифицированных объектов из памяти.
Parfik Уровень 12
23 февраля 2025
Можно ли метод set вставить в конструктор? Например у входящего параметра может быть куча ограничений и они все описаны в сеттере, можно ли не дублировать проверку из сеттера в конструкторе, а просто вызвать метод set? Насколько это будет правильно?
Vladislav Terekh Уровень 14
23 марта 2025
Конструктор ты вызываешь единожды, при создании объекта. Сеттером ты пользуешься на протяжении жизни объекта. Иными словами, чтобы повышать зарплату - её надо сначала начать получать. В конструкторе ты делаешь проверку на "свои минимальные ожидания", а в сеттере - предотвращаешь "падение и остановку роста ЗП". Говоря в контексте значений: в конструкторе ты сравниваешь с единственным значением, в сеттере ты сравниваешь уже со значением переменной, которая постоянно меняется.
Жуков Богдан Уровень 26
30 марта 2025
Можно ли метод set вставить в конструктор? Можно ли в методе вызвать другой метод? Если да, то зачем? (извини, что вопросом на вопрос) можно ли не дублировать проверку из сеттера в конструкторе, а просто вызвать метод set? Насколько это будет правильно? Конструктор нужен для того, чтобы создать объект. Геттеры и сеттеры это некая условность, которая нужна для того, чтобы либо отдать, либо поменять какую-то характеристику объекта. Тут еще вопрос в том, насколько тебе нужно использовать геттеры и сеттеры в твоем коде:)
Anton Уровень 17
19 февраля 2025
а где дыры ? Этап 1: После создания объектов и Этап 2: Появление «дыр» одинаковые
Emulsifier Уровень 11
19 февраля 2025
Дыры - это серые области: 1, 4, 6, 7. Предполагается, что эти объекты( 1, 4, 6,7) больше не достижимы, т.е. по другому память которая не используется (дыры). Для Java машины эта память становится свободной для записи.
Anton Уровень 17
20 февраля 2025
Спасибо! Теперь понятно!
Victor Уровень 29
17 января 2025
дописал в конструкторы вывод на консоль: по умолчанию System.out.println(color + ", " + year + ", " + body); с параметрами System.out.println(this.color + ", " + this.year + ", " + this.body); а методе main такое: public static void main(String[] args) { Scanner console = new Scanner(System.in); System.out.println("Напишите какой кузов вы желаете - "); String newBody = console.nextLine(); //вводим новый кузов - например кабриолет без дверей Bugatti oldCar = new Bugatti(); oldCar.setBody(newBody); Bugatti newCar = new Bugatti("WHITE", 2024, body); } Получилась целая программа со вводом и выводом.
Roman Уровень 55
6 января 2025
"Вот как это сделал бы программист-новичок: А вот как это бы сделал опытный Java-программист:"
29 января 2025
🤣
Anonymous #3312942 Уровень 19
6 января 2025
/* Комментарий удален */
Кирилл Уровень 1
27 декабря 2024
Допустим, вы хотите создать класс, который описывает точку на плоскости x и y. Вот как это сделал бы программист-новичок: и правильно бы сделал!!! может мы будем учиться азам а не ленейками меряться логарифмическими и воду лить
Yasin Akhmadov Уровень 21
26 декабря 2024
Когда прочёл заголовок "Время жизни объекта" стало очень грустно, почти на слезу пробило. Я ненормальный?
Shori Уровень 23
7 февраля 2025
сгусток эмпатии