Привет! Сегодняшнюю лекцию посвятим инкапсуляции и начнем ее сразу с примеров :) Принципы инкапсуляции - 1Перед тобой — привычный автомат с газировкой. У меня к тебе один вопрос: а как он работает? Попробуй ответить подробно: откуда вываливается стакан, как поддерживается температура внутри, где хранится лед, как автомат понимает, какой сироп добавить и т.д. Вероятнее всего, ответов на эти вопросы у тебя нет. Хорошо, возможно не все пользуются такими автоматами, в нынешнее время они не настолько популярны. Попробуем привести другой пример. Что-нибудь, чем ты точно пользуешься много раз каждый день. О, есть идея! Принципы инкапсуляции - 2 Расскажи, как работает поисковик Google. Как именно он ищет информацию по тем словам, которые ты ввел? Почему наверху находятся эти результаты, а не другие? Хотя ты пользуешься гуглом каждый день, скорее всего, ты этого не знаешь. Но это не важно. Ведь тебе и не нужно этого знать. Ты можешь вводить запросы в поисковик не задумываясь, как именно он работает. Ты можешь купить газировку в автомате, не зная как он устроен. Ты можешь водить машину, не вникая в работу двигателя внутреннего сгорания, и вообще не зная физику даже на школьном уровне. Все это возможно благодаря одному из главных принципов объектно-ориентированного программирования — инкапсуляции. Читая разные статьи на эту тему, наверняка ты сталкивался с тем, что в программировании есть два распространенных понятия — инкапсуляция и сокрытие. И под словом «инкапсуляция» авторы понимают то одно, то другое (так уж сложилось). Мы разберем оба термина, чтобы у тебя было полное понимание. Изначальное значение слова «инкапсуляция» в программировании — объединение данных и методов работы с этими данными в одной упаковке («капсуле»). В Java в роли упаковки-капсулы выступает класс. Класс содержит в себе и данные (поля класса), и методы для работы с этими данными. Принципы инкапсуляции - 3 Тебе это кажется очевидным, но в других концепциях программирования все устроено иначе. Например, в функциональном программировании данные строго отделены от операций над ними. В ООП же (объектно-ориентированном программировании) программы состоят из классов-капсул, которые являются одновременно и данными, и функциями для работы с ними. Теперь поговорим о сокрытии. Как же так получается, что мы пользуемся всякими сложными механизмами без понимания, как они устроены и на чем основана их работа? Все просто: их создатели предоставили простой и удобный интерфейс. На автомате с газировкой интерфейс — это кнопки на панели. Нажав одну кнопку, ты выбираешь объем стакана. Нажав вторую, выбираешь сироп. Третья отвечает за добавление льда. И это все, что тебе нужно сделать. Неважно, как именно автомат устроен внутри. Главное — он устроен так, что для получения газировки пользователю нужно нажать три кнопки. То же и с автомобилем. Неважно, что там происходит у него внутри. Главное — при нажатии правой педали автомобиль едет вперед, а при нажатии левой — тормозит. Именно в этом заключается суть сокрытия. Все «внутренности» программы скрываются от пользователя. Для него эта информация является лишней, ненужной. Пользователю необходим конечный результат, а не внутренний процесс. Давай для примера посмотрим на класс 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;

}
В такой ситуации можно пристально следить за тем, не создает ли кто-то из твоих коллег объектов с неправильным состоянием, но гораздо лучше было бы исключить саму возможность создавать такие «неправильные объекты». Принципы инкапсуляции - 4 С сокрытием данных нам помогают:
  1. модификаторы доступа (private, protected, package default);
  2. геттеры и сеттеры.
Туда можем, например, заложить проверку, не пытается ли кто-то присвоить коту отрицательное число в качестве возраста. Как мы говорили ранее, авторы разных статей об инкапсуляции имеют в виду либо инкапсуляцию (объединение данных и методов), либо сокрытие, либо и то, и другое. В Java присутствуют оба механизма (в других ООП-языках это не обязательно так), так что последний вариант будет наиболее правильным. Использование инкапсуляции дает нам несколько важных преимуществ:
  1. Контроль за корректным состоянием объекта. Примеры этому были выше: благодаря сеттеру и модификатору private, мы обезопасили нашу программу от котов с весом 0.

  2. Удобство для пользователя за счет интерфейса. Мы оставляем «снаружи» для доступа пользователя только методы. Ему достаточно вызвать их, чтобы получить результат, и совсем не нужно вникать в детали их работы.

  3. Изменения в коде не отражаются на пользователях. Все изменения мы проводим внутри методов. На пользователя это не повлияет: он как писал auto.gas() для газа машины, так и будет писать. А то, что мы поменяли что-то в работе метода gas() для него останется незаметным: он, как и раньше, просто будет получать нужный результат.
undefined
3
Задача
Java Core, 1 уровень, 5 лекция
Недоступна
Набираем код Ӏ Java Core: 1 уровень, 5 лекция
Java Core: 1 уровень, 5 лекция. Иногда думать не надо, строчить надо! Как ни парадоксально звучит, порой пальцы «запоминают» лучше, чем сознание. Вот почему во время обучения в секретном центре JavaRush вы иногда встречаете задания на набор кода. Набирая код, вы привыкаете к синтаксису и зарабатываете немного материи. А ещё — боретесь с ленью.
undefined
3
Задача
Java Core, 1 уровень, 5 лекция
Недоступна
Набираем больше кода Ӏ Java Core: 1 уровень, 5 лекция
Java Core: 1 уровень, 5 лекция. Внимание! Объявляется набор кода на JavaRush. Для этого включите режим повышенной внимательности, расслабьте пальцы, читайте код и… набирайте его в соответствующем окошке. Набор кода — вовсе не бесполезное занятие, как может показаться на первый взгляд: благодаря ему новичок привыкает к синтаксису и запоминает его (современные IDE редко дают ему это сделать).