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

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

Открыта

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;
   }
}


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-машина просто копирует все достижимые объекты в новое место, а всю область памяти со старыми объектами объявляет свободной.

Комментарии (271)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Anonymous #6463865
Уровень 12
20 октября, 07:15
лайк плеаз для ачивки
package com.javarush.task.pro.task10.task1008;
/* Зарплата */

public class Programmer {
    private int salary = 1000;

    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = Math.max(salary, this.salary);
    }

}
Euraks Backend Developer
26 сентября, 15:38
🦔
командир майонеза капитан кетчупа
23 февраля, 09:48
Есть хорошее видео на эту тему: https://www.youtube.com/watch?v=PA8z44ludgc Достаточно посмотреть 15 минут для того, чтобы отложилось в голове.
Grigoryvvv
Уровень 28
Expert
2 декабря 2025, 18:22
02.12.2025 / 11 уровень
REK.QA
Уровень 13
13 июля 2025, 06:07
Первая задача, правильное решение. Конструктор по умолчанию, это, типа тот, который компилятор сам создаёт при его отсутствии? На кой так путать? public class Bugatti { private String color = "BLACK"; private int year = 2020; private String body = "Coupe"; public String getBody() { return body; } public void setBody(String body) { this.body = body; } }
Christina
Уровень 15
20 ноября 2025, 14:49
никто никого не путает, в прошлых статьях же писали об этом, что в коде есть конструктор по умолчанию до тех пор, пока программист не напишет его сам в каком-нибудь классе. Это уточнение, чтоб обучающийся не писал никаких конструкторов и решал задачу только через геттеры и сеттеры..
Anonymous #3585174
Уровень 33
23 июня 2025, 16:56
like
Anonymous #3533104
Уровень 12
28 мая 2025, 14:40
расскажите пожалуйста почему у нас сетер возвращает void
Ruslan QA Automation Engineer
28 мая 2025, 16:40
Основная задача сеттера - изменить значение поля класса, а не возвращать какой-либо результат. Если поменять тип на int вместо void, то IDE сразу заругается на отсутствие оператора return.
Anonymous #3533104
Уровень 12
29 мая 2025, 10:46
аа окей
Danya Java Developer
1 апреля 2025, 21:09
Топовое обьяснение от GPT: Представь, что у тебя есть коробка (это будет наш объект), в которой ты хранишь свои игрушки (это будут поля). Ты хочешь, чтобы другие люди могли узнать, какие игрушки в коробке (это геттер), или положить туда новые игрушки (это сеттер). Но ты не хочешь, чтобы они могли просто взять коробку и без твоего разрешения поменять или вытащить игрушки. Геттер — это как ключик, который позволяет другим людям посмотреть, какие игрушки в коробке. Они могут открыть коробку и посмотреть, но не могут что-то там менять. Сеттер — это как ключик, который позволяет другим людям положить новые игрушки в коробку, но ты решаешь, какие именно игрушки можно положить, а какие нет. Например, если кто-то пытается положить игрушку, которая слишком большая, ты можешь сказать "нет, это не пройдет".
Anonymous #3533104
Уровень 12
28 мая 2025, 14:10
блен ну это топчик
15 марта 2025, 18:35
В 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, 11:18
Можно ли метод set вставить в конструктор? Например у входящего параметра может быть куча ограничений и они все описаны в сеттере, можно ли не дублировать проверку из сеттера в конструкторе, а просто вызвать метод set? Насколько это будет правильно?
Vladislav Terekh
Уровень 34
23 марта 2025, 23:02
Конструктор ты вызываешь единожды, при создании объекта. Сеттером ты пользуешься на протяжении жизни объекта. Иными словами, чтобы повышать зарплату - её надо сначала начать получать. В конструкторе ты делаешь проверку на "свои минимальные ожидания", а в сеттере - предотвращаешь "падение и остановку роста ЗП". Говоря в контексте значений: в конструкторе ты сравниваешь с единственным значением, в сеттере ты сравниваешь уже со значением переменной, которая постоянно меняется.
Жуков Богдан Системный аналитик
30 марта 2025, 13:34
Можно ли метод set вставить в конструктор? Можно ли в методе вызвать другой метод? Если да, то зачем? (извини, что вопросом на вопрос) можно ли не дублировать проверку из сеттера в конструкторе, а просто вызвать метод set? Насколько это будет правильно? Конструктор нужен для того, чтобы создать объект. Геттеры и сеттеры это некая условность, которая нужна для того, чтобы либо отдать, либо поменять какую-то характеристику объекта. Тут еще вопрос в том, насколько тебе нужно использовать геттеры и сеттеры в твоем коде:)
Дени Ахмадов
Уровень 18
2 августа 2025, 11:27
ты просто по сути создаешь метод в методе, а это невозможно.