Инкапсуляция в Java это принцип ООП, который объединяет данные (поля) и методы работы с ними в одном классе-«капсуле» и скрывает внутреннее устройство объекта от пользователя. На практике ее реализуют так: поля закрывают модификатором
private, а доступ к ним дают через
public-методы (геттеры и сеттеры), в которых можно проверить корректность данных.
Привет! Сегодняшнюю лекцию посвятим инкапсуляции и начнем ее сразу с примеров :)
Кратко
- Инкапсуляция это объединение данных (полей) и методов работы с ними в одной «капсуле», классе.
- Сокрытие реализации: пользователю дают простой интерфейс (методы), а внутреннюю работу прячут.
- Сокрытие данных: поля закрывают модификатором
private и дают доступ через геттеры и сеттеры.
- В Java «инкапсуляция» обычно означает и объединение, и сокрытие вместе.
- Сеттеры позволяют проверять данные и не допускать некорректного состояния объекта (например, отрицательный возраст).
- Плюсы: контроль состояния объекта, удобный интерфейс, свобода менять внутренний код без вреда для пользователей.
Перед тобой привычный автомат с газировкой. У меня к тебе один вопрос: а как он работает? Попробуй ответить подробно: откуда вываливается стакан, как поддерживается температура внутри, где хранится лед, как автомат понимает, какой сироп добавить и т.д.
Вероятнее всего, ответов на эти вопросы у тебя нет. Хорошо, возможно не все пользуются такими автоматами, в нынешнее время они не настолько популярны.
Попробуем привести другой пример. Что-нибудь, чем ты точно пользуешься много раз каждый день. О, есть идея!
![Поисковиком Google пользуются, не зная его внутреннего устройства: пример сокрытия]()
Расскажи, как работает
поисковик Google. Как именно он ищет информацию по тем словам, которые ты ввел? Почему наверху находятся эти результаты, а не другие?
Хотя ты пользуешься гуглом каждый день, скорее всего, ты этого не знаешь. Но это не важно.
Ведь тебе и не нужно этого знать.
Ты можешь вводить запросы в поисковик не задумываясь, как именно он работает. Ты можешь купить газировку в автомате, не зная как он устроен. Ты можешь водить машину, не вникая в работу двигателя внутреннего сгорания, и вообще не зная физику даже на школьном уровне.
Все это возможно благодаря одному из главных принципов
объектно-ориентированного программирования,
инкапсуляции.
Читая разные статьи на эту тему, наверняка ты сталкивался с тем, что в программировании есть два распространенных понятия,
инкапсуляция и
сокрытие. И под словом «инкапсуляция» авторы понимают то одно, то другое (так уж сложилось). Мы разберем оба термина, чтобы у тебя было полное понимание.
Кратко все три механизма удобно свести в таблицу:
| Понятие | Что означает | Как реализуется в Java |
| Инкапсуляция (объединение) | данные и методы работы с ними лежат в одной капсуле | класс с полями и методами |
| Сокрытие реализации | скрыть внутреннюю работу, дать простой интерфейс | public-методы наружу, логика внутри |
| Сокрытие данных | защитить поля от прямого доступа | private-поля + геттеры и сеттеры |
Инкапсуляция: объединение данных и методов
Изначальное значение слова «
инкапсуляция» в программировании это
объединение данных и методов работы с этими данными в одной упаковке («капсуле»).
В Java в роли упаковки-капсулы выступает
класс. Класс содержит в себе и
данные (поля класса), и
методы для работы с этими данными.
![Класс как капсула: объединяет данные (поля) и методы работы с ними]()
Тебе это кажется очевидным, но в других концепциях программирования все устроено иначе. Например, в функциональном программировании данные строго отделены от операций над ними.
В ООП же (объектно-ориентированном программировании) программы состоят из классов-капсул, которые являются одновременно и данными, и функциями для работы с ними.
Сокрытие реализации
Теперь поговорим о
сокрытии.
Как же так получается, что мы пользуемся всякими сложными механизмами без понимания, как они устроены и на чем основана их работа? Все просто: их создатели предоставили простой и удобный
интерфейс.
На автомате с газировкой интерфейс это кнопки на панели. Нажав одну кнопку, ты выбираешь объем стакана. Нажав вторую, выбираешь сироп. Третья отвечает за добавление льда. И это все, что тебе нужно сделать.
Неважно, как именно автомат устроен внутри. Главное,
он устроен так, что для получения газировки пользователю нужно нажать три кнопки.
То же и с автомобилем. Неважно, что там происходит у него внутри. Главное,
при нажатии правой педали автомобиль едет вперед, а при нажатии левой тормозит.
Именно в этом заключается суть сокрытия. Все «внутренности» программы скрываются от пользователя. Для него эта информация является лишней, ненужной. Пользователю необходим конечный результат, а не внутренний процесс.
Давай для примера посмотрим на класс
Auto:
public class Auto {
public void gas() {
/*внутри автомобиля происходят какие-то сложные вещи
в результате которых он едет вперед*/
}
public void brake() {
/*внутри автомобиля происходят какие-то сложные вещи
в результате которых он тормозит*/
}
public static void main(String[] args) {
Auto auto = new Auto();
//Как все выглядит для пользователя
//нажал одну педаль - поехал
auto.gas();
//нажал другую педаль - затормозил
auto.brake();
}
}
Вот как выглядит сокрытие реализации в Java-программе. Все как в реальной жизни: пользователю предоставлен интерфейс (методы). Если ему нужно, чтобы автомобиль в программе выполнил действие, достаточно вызвать нужный метод. А уж что там происходит внутри этих методов это информация лишняя, главное, чтобы все работало как надо.
Сокрытие данных
Здесь мы говорили про
сокрытие реализации. Кроме него в Java есть еще
сокрытие данных. О нем мы писали в
лекции про геттеры и сеттеры, но не будет лишним напомнить.
Например, у нас есть класс
Cat:
public class Cat {
public String name;
public int age;
public int weight;
public Cat(String name, int age, int weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
public Cat() {
}
public void sayMeow() {
System.out.println("Мяу!");
}
}
Возможно, ты запомнил из прошлой лекции, в чем проблема этого класса? Если нет, давай вспомним.
Проблема в том, что его данные (поля) открыты для всех, и другой программист легко может создать в программе безымянного кота с весом 0 и возрастом -1000 лет:
public static void main(String[] args) {
Cat cat = new Cat();
cat.name = "";
cat.age = -1000;
cat.weight = 0;
}
В такой ситуации можно пристально следить за тем, не создает ли кто-то из твоих коллег объектов с неправильным состоянием, но гораздо лучше было бы исключить саму возможность создавать такие «неправильные объекты».
![Без сокрытия данных можно создать объект с некорректным состоянием]()
С сокрытием данных нам помогают:
- модификаторы доступа (private, protected, package default);
- геттеры и сеттеры.
Туда можем, например, заложить проверку, не пытается ли кто-то присвоить коту отрицательное число в качестве возраста.
Как мы говорили ранее, авторы разных статей об инкапсуляции имеют в виду либо инкапсуляцию (объединение данных и методов), либо сокрытие, либо и то, и другое. В Java присутствуют оба механизма (в других ООП-языках это не обязательно так), так что последний вариант будет наиболее правильным.
Преимущества инкапсуляции
Использование инкапсуляции дает нам несколько важных преимуществ:
- Контроль за корректным состоянием объекта. Примеры этому были выше: благодаря сеттеру и модификатору private, мы обезопасили нашу программу от котов с весом 0.
- Удобство для пользователя за счет интерфейса. Мы оставляем «снаружи» для доступа пользователя только методы. Ему достаточно вызвать их, чтобы получить результат, и совсем не нужно вникать в детали их работы.
- Изменения в коде не отражаются на пользователях. Все изменения мы проводим внутри методов. На пользователя это не повлияет: он как писал auto.gas() для газа машины, так и будет писать. А то, что мы поменяли что-то в работе метода gas() для него останется незаметным: он, как и раньше, просто будет получать нужный результат.
Больше о разграничении доступа к полям и методам класса можно прочитать в
документации Oracle (Controlling Access to Members of a Class).
Читайте также
Вопросы и ответы
Что такое инкапсуляция в Java?
Это принцип ООП, который объединяет данные (поля) и методы работы с ними в одном классе-«капсуле», а также скрывает внутреннее устройство объекта от пользователя.
Чем инкапсуляция отличается от сокрытия?
Инкапсуляция в узком смысле это объединение данных и методов в классе. Сокрытие это ограничение доступа к внутренностям (реализации и данным). В Java под инкапсуляцией обычно понимают оба механизма вместе.
Что такое сокрытие данных?
Это защита полей объекта от прямого доступа: поля делают
private, а читать и менять их дают только через геттеры и сеттеры, где можно проверить корректность значений.
Как реализовать инкапсуляцию в Java?
Закрыть поля модификатором
private, а доступ к ним организовать через
public-методы (геттеры и сеттеры). Внутреннюю логику держать внутри методов, наружу отдавать только интерфейс.
Зачем нужны геттеры и сеттеры?
Они дают контролируемый доступ к
private-полям: в сеттере можно проверить входные данные и не допустить некорректного состояния объекта, например отрицательного возраста.
Какие преимущества дает инкапсуляция?
Контроль за корректным состоянием объекта, удобный интерфейс для пользователя и возможность менять внутренний код, не затрагивая тех, кто пользуется классом.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ