# Encapsulation
Imagine you had a class with some pretty important variables and they were set (by other programmers from their code) to unacceptable values.Their code brought errors in your code. As a solution, In OOP, you allow the state of an object (stored in its variables) to be modified only through methods. Hiding the state of an object and providing all interaction through an objects methods is known as Data Encapsulation.
# Encapsulation to maintain invariants
There are two parts of a class: the interface and the implementation.
The interface is the exposed functionality of the class. Its public methods and variables are part of the interface.
The implementation is the internal workings of a class. Other classes shouldn’t need to know about the implementation of a class.
Encapsulation refers to the practice of hiding the implementation of a class from any users of that class. This allows the class to make assumptions about its internal state.
For example, take this class representing an Angle:
This class relies on a basic assumption (or invariant): angleInDegrees and angleInRadians are always in sync. If the class members were public, there would be no guarantees that the two representations of angles are correlated.
# Encapsulation to reduce coupling
Encapsulation allows you to make internal changes to a class without affecting any code that calls the class. This reduces coupling, or how much any given class relies on the implementation of another class.
For example, let’s change the implementation of the Angle class from the previous example:
The implementation of this class has changed so that it only stores one representation of the angle and calculates the other angle when needed.
However, the implementation changed, but the interface didn’t. If a calling class relied on accessing the angleInRadians method, it would need to be changed to use the new version of Angle . Calling classes shouldn’t care about the internal representation of a class.
# Remarks
It is much easier to start with marking a variable private and expose it if necessary than to hide an already public variable.
There is one exception where encapsulation may not be beneficial: "dumb" data structures (classes whose sole purpose is to hold variables).
In this case, the interface of the class is the data that it holds.
Note that variables marked final can be marked public without violating encapsulation because they can’t be changed after being set.
Кофе-брейк #166. Зачем нужна инкапсуляция в Java? Три способа использования функции Print в Java

Источник: Use My Notes Из этой публикации вы узнаете, зачем нужна инкапсуляция в объектно-ориентированном программировании. В статье рассмотрена концепция ее работы и способы реализации на языке Java.
Что такое инкапсуляция в Java
Зачем нам нужна инкапсуляция в Java?
- Чтобы код оставался чистым и организованным.
- Для лучшего контроля доступа к инкапсулированным членам.
- Чтобы лучше понимать код.
Как концепция инкапсуляции может помочь в работе?
- Помогает организовать код лучше и понятнее.
- Позволяет прилагать меньше усилий при сопровождении большого количества кода.
- Снижает сложность управления кодом.
- Разделяет код на части.
- Повышает читабельность.
А если бы инкапсуляции не было?
- Код может стать неорганизованным или беспорядочным.
- Увеличивается сложность поддержки кода.
- Усложняется отладка кода.
- Снижается читабельность.
Три способа использования функции Print в Java

Источник: FreeCodeCamp Далеко не все разработчики знают о трех разных функциях/операторах Print в Java. Автор этой статьи расскажет о них и покажет, как они работают на примерах.
Инкапсуляция в Java

Привет! Это статья про инкапсуляцию — один из принципов ООП. Если Вы не знаете, что такое принципы ООП — почитайте эту статью:
Что такое инкапсуляция
В программировании очень важна безопасность. В ООП безопасность обеспечивается по-своему — с помощью принципа инкапсуляции (с англ. «encapsulation»). Инкапсуляцию можно перевести как «положить что-то во что-то», или для простоты «обернуть в капсулу»

С помощью инкапсуляции мы защищаем данные от неправомерного использования.
Если еще проще
Как не удивительно, мы можем видеть инкапсуляцию и в повседневной жизни. Например, Ваше имя и фамилия находится в относительно свободном доступе — они известны всем Вашим знакомым. Но Вы не хотели бы, чтобы кто-то знал номер Вашей кредитки и ее пинкод? Если проводить аналогию с методами, Вы не хотели бы, чтобы кто-то, например, ездил на Вашей машине, спал в Вашей кровати и ел Вашу кашу? Даже свои секреты мы доверяем ограниченному числу людей — можно сказать регулируем права доступа.
Для того, чтобы никто не получил доступ к тому, что не следует, мы пользуемся разными средствами для обеспечения безопасности — ставим замки на двери, пароль на телефон или ноутбук, и т.д.

Точно так же и в Java — мы пользуемся разными средствами для обеспечения принципа инкапсуляции. Но как же мы это делаем?
Как применяется инкапсуляция
Есть несколько способов регулировать доступ к нашим данным. Основные это:
- Модификаторы доступа (Access modifiers)
- Геттеры и Сеттеры (Getters and Setters)
Модификаторы доступа
Модификаторы доступа — это специальные слова, которые показывают, кому нельзя, а кому можно пользоваться данными.
Существуют четыре модификатора доступа:

На самом деле по названиям не сложно понять, что каждый из них означает:
- public — «публичный, доступный всем»
- default — «по умолчанию». Когда мы не пишем модификатора доступа (как мы это делали в наших предыдущих уроках), он по умолчанию имеет значение default. Данные с этим модификатором видны в пределах package.
- protected — «защищенный». На самом деле это то же самое, что и default, только доступ имеют еще и классы-наследники.
- private — «частный, личный». Такие данные видны только самому классу.
Модификаторы доступа пишутся перед названиями переменных, методов и даже классов:

Как это обеспечивает безопасность? Давайте попробуем создать класс, в котором будет только одна переменная — String s. Допустим она имеет модификатор public:
Name already in use
JBook / oop / encapsulation.md
- Go to file T
- Go to line L
- Copy path
- Copy permalink
- Open with Desktop
- View raw
- Copy raw contents Copy raw contents
Copy raw contents
Copy raw contents
Слово Инкапсуляция происходит от лат. in capsula , capsula — «коробочка».
Инкапсуляция — механизм, позволяющий объединить данные и методы, работающие с этими данными, в единый объект и скрыть детали реализации от пользователя.
Грамотно написанный класс должен ограничивать доступность своих членов и взаимодействовать с пользователем только с помощью своего интерфейса. Для этого необходимо четко и ясно понимать то, как вы представляете взаимодействие вашего класса и других частей программы, а все, что не входит в интерфейс скрывать.
Если следовать заветам Джошуа Блоха: главное правило заключается в том, чтобы сделать каждый класс или член максимально недоступным.
Представьте себе автомобиль. По сути, все, что является внутренностями машины, скрыто от вас, а открытое API — это руль и педали. Т.е все, что вам доступно — это только то, что вам необходимо для взаимодействия с объектом, в нашем случае — с автомобилем.
Если этого не было, то пользователю объекта предоставлялся бы полный доступ к реализации, ко всем составляющим объекта.
Теперь представьте, какую опасность в себе таит полный доступ до составляющих для любого пользователя. Эта ситуация похожа на ту, где вы дали root доступ на вашем сервере или компьютере для всех пользователй интернета.
Как вы думаете: как долго ваша система проживет?
Возвращаясь к примеру с машиной: нарушение инкапсуляции может привести к поломке автомобиля просто потому, что водитель или пассажир по ошибке, а может и ради интереса, воткнут соломинку в двигатель. Во время движения.
Я думаю этих примеров достаточно для того, чтобы вы, как разработчик и пользователь, поняли значимость инкапсуляции и не пренебрегали ей.
Java , как ООП язык, предоставляет нам несколько инструментов для обеспечения инкапсуляции : модификаторы доступа и пакеты.
В начале давайте поговорим про то, что такое пакет .
Представим, что в нашем проекте несколько сотен, а то и тысяч классов.
В большинстве случаев в Java каждый класс определяется в отдельном файле.
Я думаю, вы уже начали догадываться к чему я клоню: представьте тысячу файлов в одной директории! А если классов более тысячи? Или же вы подключили стороннюю библиотеку, в которой есть классы, с такими же именами, что и у вас в проекте?
В таком хаосе нельзя остаться верным императору и не запутаться во тьме.
Логично, что надо попытаться структурировать их: разнести по нескольким директориям, тем самым создать дерево директорий, в котором легко ориентироваться. Именно это и сделано в Java . Только вместо директории мы говорим пакет .
Для описания того, что класс относится к пакету используется ключевое слово package .
Пакеты иерархичны, эта иерархия описывается через . , поэтому точка не может быть в имени пакета. Пакет, которому принадлежит класс, всегда описывается в самом начале исходного файла.
Это описание, если оно есть, должно быть первым, только комментарии могут быть раньше него.
Таким образом класс HashUtils принадлежит пакету hash , который является вложенным в пакет utils , который в свою очередь также вложен в aarexer .
Существует также некоторое джентльменское соглашение: для обеспечения уникальности имен пакетов принято в начало добавлять реверсированный домен второго уровня разработчика пакета. Т.е если у вас есть домен aarexer.ru , то имена пакетов начинаться должны с ru.aarexer .
Этому джентльменскому соглашению придерживается большинство компаний и разработчиков, например, класс FileUtils у apache-commons лежит в пакете:
Имя пакета является частью полного имени класса, это весьма важный момент. Полное имя класса, содержащее имя пакета, решает еще одну важную задачу — уникальность имен классов. И потому появляется возможность создавать классы с одним именем, но в разных пакетах.
В качестве примера можно привести: java.awt.List и java.util.List . Это два разных класса с одним названием, однако, благодаря тому, что они логически разделены пакетами, а пакет является частью полного имени класса, все становится на свои места.
Разделение на пакеты
В пакет объединяются классы, которые тесно связаны друг с другом логически.
Примерами могут служить пакет java.swing , где собраны классы отвечающие за работу с библиотекой swing или же пакет javafx.scene.control , где можно найти все для работы с контролами — кнопки, комбо-боксы и т.д
Т.е пакеты — это некоторая структурная единица в разработке, группирующая логически классы. И это дополнительный инструмент для инкапсуляции!
Например, вы пишите библиотеку, где внутренние компоненты взаимодействуют посредством класса Event — событий. Т.е ваши внутренние компоненты пересылают друг другу события, вы вводите сущность некоторого служебного события. Этот класс — внутренний для нашей библиотеки, мы не хотим и не собираемся его ‘светить’ наружу, так как он нужен нам только для внутреннего использования.
В таком случае мы выносим такой класс в пакет и применяем модификатор доступа package .
Доступ мне и всем в пределах пакета, всем соседям.
Скроем наш класс от разработчиков, которые будут пользоваться нашей библиотекой, но при этом в использовании не ограничим.
Теперь поговорим про модификаторы доступа.
Модификатор доступа — это ключевое слово Java для задания области видимости полей, методов и классов.
В Java существует целых 4 модификатора доступа:
Доступ всем и отовсюду .
К полям, методам и классам, объявленным как public доступ имеет кто угодно.
Доступ мне и только мне .
К полям, методам и классам, объявленным как private , имеет доступ только класс , в котором они объявлены.
Доступ мне и всем в пределах пакета, всем соседям
К полям, методам и классам, объявленным package , имеет доступ не только класс , в котором они объявлены, но и все классы , находящиеся в том же самом пакете . Это модификатор доступа по-умолчанию, если вы не указали иного.
Доступ мне и всем наследникам
К полям, методам и классам, объявленным как protected , имеет доступ класс , в котором они объявлены, все классы , находящиеся в том же самом пакете и все классы -потомки, все классы, унаследованные от того, где сделано объявление.
Крайне важно помнить, что в Java модификатор доступа protected дает также доступ и всем в пакете! Это очень странное решение от создателей, однако так сделано и это просто надо помнить.
Сведем все в одну таблицу для наглядности:
| Модификатор доступа | Границы видимости | Описание |
|---|---|---|
| public | Доступ всем и отовсюду . | К полям, методам и классам, объявленным как public доступ имеет кто угодно. |
| private | Доступ мне и только мне . | К полям, методам и классам, объявленным как private , имеет доступ только класс , в котором они объявлены. |
| package | Доступ мне и всем в пределах пакета, всем соседям | К полям, методам и классам, объявленным package , имеет доступ не только класс , в котором они объявлены, но и все классы , находящиеся в том же самом пакете . |
| protected | Доступ мне и всем наследникам | К полям, методам и классам, объявленным как protected , имеет доступ класс , в котором они объявлены, все классы , находящиеся в том же самом пакете и все классы -потомки. |
Модификаторы доступа и наследование
При переопределении метода у класса наследника, мы не можем изменить модификатор доступа на более закрытый.
Например, если метод public , то в классе наследнике не получится уровень доступа изменить на private .
Что довольно логично, раз класс-родитель предоставляет нам свой метод в качестве открытого, то и класс-потомок не должен ограничивать доступ к этому методу, так как иначе изменится интерфейс класса. Это сделано для того, чтобы гарантировать, что объект класса-наследника мы можем использовать везде, где можно было бы использовать объект супер-класса.
Это отсылает нас к SOLID, а если быть точнее, то к L — The Liskov Substitution Principle.
Класс наследник должен дополнять, а не изменять базовый.
Советы по использованию
Главное правило, повторюсь, сделать ваш код максимально закрытым, сделать так, чтобы пользоваться можно было лишь тем, что действительно необходимо.
Если ваш класс используется только в области видимости пакета — сделайте такой класс доступным только в пакете с помощью package . Тогда такой класс перестанет быть доступным извне, он станет частью реализации пакета.
В таком случае, даже если вы как-то измените логику этого класса или вообще удалите его, вы будете точно уверены, что не сломаете ничего у пользователей вашего кода. Оставив такой класс открытым, вы будете обязаны поддерживать работоспособность класса, поддерживать совместимость и прочее.
Модификатор доступа protected используется в основном тогда, когда вы планируете использовать это поле/метод в наследовании. После public это наиболее открытый модификатор. Соответсвенно, исходя из описания, не следует применять его вне того, для чего он обычно используется.
Наиболее часто злоупотребляют использованием модификатора public , поэтому разберем его подробнее.
Когда вы объявляете поле или метод как public вы по сути включаете его в API класса.
В случае, если это действительно часть API , без которого взаимодействие с классом и его объектами невозможно — это оправдано.
Но в тех случаях, когда это не относится к API — это уже вредная и пагубная практика, которая может привести к неподдерживаемому коду, трудноуловимым ошибкам и плохому сну(как вашему, так и людей, которые используют ваш код).
Почему? Давайте разбираться!
В случае, когда мы делаем метод public , надо понимать, что мы даем возможность его использования всем. Тем самым мы вносим такой метод в интерфейс класса.
Давайте опять сядем в автомобиль и посмотрим на приборную панель. Огромное многообразие кнопок и рычагов — это интерфейс.
Грубо говоря, каждой кнопке и рычагу соответствует какой-то метод. Если вы добавляете функцию автоматических дворников — логично, что этому должна соответствовать какая-то кнопка, т.е это public -метод. А вот если вы делаете функцию подачи горючего в двигатель, то выносить это на приборную панель — губительная практика.
Так как вам, как создателю, наверняка ясно когда эту кнопку нажимать, а вот обыкновенному пользователю совершенно нет. И вероятность того, что он ее нажмет не в то время и не в том месте приближается к катастрофическим 100%.
Поэтому отдавайте себе отчет: что выносить в интерфейс класса, а что нет.
Чего надо опасаться, когда объявляем public поле и о чем надо задумываться?
В первую очередь, это то, что большинство объектов в Java — изменяемые. И ссылки на объекты по умолчанию тоже изменяемые.
Это значит, что задав public на такое поле кто-то просто может изменить не только состояние вашего объекта, но и поведение!
Приведем простой приме, у нас есть класс Person , мы сделали его в лучших традициях начинающих разработчиков:
Теперь создадим несколько экзмепляров класса и в одном из них изменим возраст:
И что же мы видим? А видим мы Александра в возрасте минус сто.
Да, этому Александру явно не повезло и в первую очередь в том, что он встретился с таким программистом, который не учел, что возраст не может быть отрицательным.
Понятно, что для того, чтобы не дать ставить всем попало его возраст и повесить некоторые ограничения на количество лет и их качество надо закрыть поле возраста.
Однако тут же встает и еще один вопрос: закрыть-то мы закроем, а как обращаться теперь к полю? И как менять возраст?
Для этих целей существуют так называемые getter -ы и setter -ы.
Давайте модернизируем наш класс:
Теперь при отрицательных числах возраста мы будем бросать исключение, тем самым не дав никому сделать Александра с отрицательным возрастом.
А обращение к полю мы получаем через специальный метод, getter , который является частю API класса.
Тем самым мы, как проектировщики, подразумеваем, что пользователь может обращаться к экземплярам класса Person и спросить у них их возраст. При этом, если мы решим, что наши персонажи не должны сообщать никому свой возраст, то мы просто уберем этот метод, закрыв поле в классе и не дав к нему доступа.
Т.е инкапсуляция — это еще и контроль за валидностью данных.
Не надо быть провидцем, чтобы почувствовать вопрос, который уже давно витает в воздухе.
Вопрос:
Когда же безопасно использовать public ?
Ответ:
С final -полями и неизменяемыми объектами.
Например, при объявлении констант.
Необходимо помнить, что final не гарантирует нам, что вы не измените сам объект(если он модифицируемый). Т.е final гарантирует лишь то, что вы не измените ссылку на объект, но сам объект может меняться.
Для объявления константы, входящей в API класса можно использовать конструкцию вида: public static final . Часто константы группируют логически и выносят в отдельные классы, например, как показано вот тут.
Также, если ваш объект не изменяемый( immutable ) и должен входить в интерфейс класса, то вполне допустимо использовать public final . Ведь объект — неизменяемый, а значит и навредить ему или изменить его нельзя, а благодаря ключевому слову final вы закрываете возможность подменить этот объект на другой.
Однако, даже использование final не спасет, если объект может менять свое состояние, т.е является изменяемым, mutable -объектом. Как например, массивы или коллекции.
Представим, что вы объявили public static final ссылку на массив или коллекцию в вашем классе. Массив — это изменяемая структура данных. В совокупности с тем, что из-за открытого доступа, ведь мы объявили массив как public , мы никак не контролируем добавление и удаление элементов в такой массив мы получаем серьезную проблему. Любой желающий может добавить или удалить элемент из такого массива, при этом мы об этом во время даже не узнаем.
Вопросы для закрепления
Если все, что вы прочли выше для вас не явилось новинкой, вы прекрасно все это знаете и считаете, что тут не может быть подводных камней, то давайте ответим на пару вопросов в порядке возрастания сложности?
Вопрос 0:
Есть ли ограничения на то, кому какой модификатор доступа поставить? Какие модификаторы доступа можно ставить полям класса? Методам? Самим классам?
Ответ:
У членов класса(полей, методов и конструкторов) ограничений нет, могут быть любые. Сами классы могут быть public и package . Внутренние классы могут быть объявлены с любым модификатором доступа, так как в этом плане не отличаются от членов класса.
Вопрос 1:
Какой модификатор доступа будет у конструктора по умолчанию?
Ответ:
Тут все просто — модификатор доступа для конструктора по умолчанию будет такой же, какой модификатор доступа у класса.
Вопрос 2:
Зачем нужен private конструктор? А protected конструктор?
Ответ:
Напомним, что конструктор — это способ инициализации экземпляра создаваемого объекта. У класса может быть несколько конструкторов, это просто несколько способов создания. Логично, что и на эти способы хотелось бы иметь возможность навешивать какие-то ограничения.
С private конструктором все довольно прозрачно. Это средство создания объектов класса, зарезервированное для нас самих и только для нас. Соответственно, в классе-наследнике вы его не вызовете.
С protected конструктором дело обстоит чуть интереснее.
Он может использоваться в двух случаях.
protected конструктор может вызываться в качестве конструктора родительского класса. Т.е через вызов super(. ) .
protected конструктор может вызываться в простой конструкции new , но только внутри пакета, где определен класс.
Вопрос 3:
Разрешен ли доступ к private методам и полям в одном экземпляре класса к другому экземпляру того же класса?
Будет ли валиден такой код?
Ответ:
Такой код валиден и разрешен.
Ограничение private не ограничивает доступ экземплярам класса друг к другу. Более того, это распространяется и на статические методы – т.е. если в статический метод класса A передать экземпляр класса A , то внутри этого метода разрешен доступ ко всем private -членам переданного экземпляра.
Вопрос 4:
А что будет, если у нас есть еще и класс наследник и он в другом пакете?
Будет ли валиден такой код?
Обратите внимание на пакеты и модификаторы доступа!
Ответ:
Нет! Такой код будет не валиден.
При этом, если мы изменим тип аргумента other с TestParent на TestChild код уже будет валидным.
Т.е доступ будет к полю или методу чужого экземпляра только если чужой экземпляр является экземпляром того же класса наследника (или унаследованного в свою очередь от него). А вот к полю или методу чужого экземпляра и при этом родительского класса – нет.
Как говорила моя учительница по английскому: «To sum up»!
Инкапсуляция — механизм, позволяющий объединить данные и методы, работающие с этими данными, в единый объект и скрыть детали реализации от пользователя.
Т.е данные и методы связаны в едином объекте. Концепция подразумевает использование объекта путем предоставления интерфейса взаимодействия и сокрытия деталей его реализации.
При помощи модификаторов доступа уже осуществляется понимание какие члены и методы класса будут являться его интерфейсом взаимодействия, а какие будут являться деталью реализации.
В Java существует четыре модификатора доступа: public , protected , package и private . Основное правило их применения в том, что чем строже уровень доступа — тем лучше.
Так как public дает доступ до поля/метода всем, то старайтесь не использовать его для изменяемых объектов, либо контролируйте изменения. Помните, что public добавляет поле/метод в API класса!