JavaRush /Java блог /Random UA /Модифікатори доступу. Private, protected, default, public...

Модифікатори доступу. Private, protected, default, public

Стаття з групи Random UA
Вітання! У сьогоднішній лекції ми познайомимося з поняттям « модифікатори доступу » та розглянемо приклади роботи з ними. Модифікатори доступу.  Private, protected, default, public - 1Хоча слово «познайомимося» буде не зовсім правильним: з більшістю з них ти вже знайомий із попередніх лекцій. Про всяк випадок освіжимо в пам'яті головне. Модифікатори доступу – це найчастіше ключові слова, які регулюють рівень доступу до різних частин твого коду. Чому «найчастіше»? Тому що один з них встановлений за замовчуванням і не позначається ключовим словом :) Всього Java має чотири модифікатори доступу. Перерахуємо їх у порядку від найсуворіших до «м'яких»:
  • private;
  • protected;
  • default (package visible);
  • public.
Давай розглянемо кожен з них, визначимося, коли вони можуть нам стати в нагоді і наведемо приклади :)

Модифікатор private

Модифікатори доступу.  Private, protected, default, public - 2Private- Найсуворіший модифікатор доступу. Він обмежує видимість даних та методів межами одного класу. Цей модифікатор тобі відомий з лекції про гетери та сеттери. Пам'ятаєш цей приклад?
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("Мяу!");
   }
}

public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       cat.name = "";
       cat.age = -1000;
       cat.weight = 0;
   }
}
Ми розглядали його в одній із статей раніше. Тут ми припустабося серйозної помилки: відкрабо наші дані, внаслідок чого колеги-програмісти отримали доступ безпосередньо до полів класу та зміни їхнього значення. Більш того, ці значення надавалися без перевірок, в результаті чого в нашій програмі можна створити кота з віком -1000 років, іменем «» і вагою 0. Для вирішення цієї проблеми ми використовували гетери та сеттери, а також обмежабо доступ до даних за допомогою модифікатора private.
public class Cat {

   private String name;
   private int age;
   private 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("Мяу!");
   }

   public String getName() {
       return name;
   }

   public void setName(String name) {
       // Перевірка вхідного параметра
       this.name = name;
   }

   public int getAge() {
       return age;
   }

   public void setAge(int age) {
       // Перевірка вхідного параметра
       this.age = age;
   }

   public int getWeight() {
       return weight;
   }

   public void setWeight(int weight) {
       // Перевірка вхідного параметра
       this.weight = weight;
   }
}
Власне, обмеження доступу до полів та реалізація геттерів-сеттерів – найпоширеніший приклад використання privateу реальній роботі. Тобто реалізація інкапсуляції у програмі – головне призначення цього модифікатора. Це стосується не лише полів, до речі. Уяви, що у твоїй програмі існує метод, який реалізує якусь ДУЖЕ складну функціональність. Що б вигадати такого для прикладу… Скажімо, твій методreadDataFromCollider()приймає на вхід адресау з даними, зчитує дані з Великого Адронного Колайдера у байтовому форматі, перетворює ці дані на текст, записує у файл і роздруковує його. Навіть опис методу виглядає моторошно, що вже говорити про код :) Щоб підвищити читання коду, було б добре не писати складну логіку методу в одному місці, а навпаки - розбити функціональність на окремі методи. Наприклад, метод readByteData()відповідає за зчитування даних, convertBytesToSymbols()конвертує лічені з колайдера дані в текст, saveToFile()зберігає отриманий текст у файл, а printColliderData()роздруковує наш файл з даними. Метод readDataFromCollider()у результаті став набагато простіше:
public class ColliderUtil {

   public void readDataFromCollider(Path pathToData) {
       byte[] colliderData = readByteData(pathToData);
       String[] textData = convertBytesToSymbols(colliderData);
       File fileWithData = saveToFile(textData);
       printColliderData(fileWithData);
   }

   public byte[] readByteData(Path pathToData) {

       // зчитує дані в байтах
   }

   public String[] convertBytesToSymbols(byte[] colliderDataInBytes) {

       // конвертує байти на символи
   }

   public File saveToFile(String[] colliderData) {

       // зберігає лічені дані у файл
   }

   public void printColliderData(File fileWithColliderData) {

       // Друкує дані з файлу
   }
}
Однак, як ти пам'ятаєш з лекції про інтерфейси, користувач отримує доступ до кінцевого інтерфейсу. А наші 4 методи не є його частиною. Вони допоміжні : ми створабо їх, щоб покращити читання коду і не засовувати чотири різні завдання в один метод. Надавати доступ користувачеві до цих методів не потрібно. Якщо у користувача під час роботи з колайдером з'явиться доступ до методу convertBytesToSymbols(), він швидше за все просто не зрозуміє, що це за метод і навіщо потрібний. Які байти конвертуються? Звідки вони взялися? Навіщо їх конвертувати у текст? Логіка, яка виконується у цьому методі, не є частиною інтерфейсу користувача. Тільки методreadDataFromCollider()- Частина інтерфейсу. Що ж робити із цими чотирма «внутрішніми» методами? Правильно! Обмежити доступ до них модифікатором private. Так вони зможуть спокійно виконувати свою роботу всередині класу і не вводити в оману користувача, якому логіка кожного окремо не потрібна.
public class ColliderUtil {

   public void readDataFromCollider(Path pathToData) {
       byte[] colliderData = readByteData(pathToData);
       String[] textData = convertBytesToSymbols(colliderData);
       File fileWithData = saveToFile(textData);
       printColliderData(fileWithData);
   }

   private byte[] readByteData(Path pathToData) {
       // зчитує дані в байтах
   }

   private String[] convertBytesToSymbols(byte[] colliderDataInBytes) {
       // конвертує байти на символи
   }

   private File saveToFile(String[] colliderData) {
       // зберігає лічені дані у файл
   }

   private void printColliderData(File fileWithColliderData) {
       // Друкує дані з файлу
   }
}

Модифікатор protected

Наступний за строгістю модифікатор доступу - protected. Модифікатори доступу.  Private, protected, default, public - 3 Поля та методи, позначені модифікатором доступу protected, будуть видні:
  • у межах всіх класів, що у тому пакеті, як і наш;
  • у межах всіх класів-спадкоємців нашого класу.
Відразу важко уявити, коли це може знадобитися. Не дивуйся: випадків застосування protectedнабагато менше, ніж private, і вони специфічні. Уяви, що у нас є абстрактний клас AbstractSecretAgent, що означає секретного агента якоїсь спецслужби, а також пакет top_secret, в якому лежить цей клас та його спадкоємці. Від нього успадковуються конкретні класи - FBISecretAgent, MI6SecretAgent, MossadSecretAgentі т.п. Усередині абстрактного класу ми хочемо продати лічильник агентів. При створенні десь у програмі нового об'єкта-агента він збільшуватиметься.
package top_secret;

public abstract class AbstractSecretAgent {

   public static int agentCount = 0;
}
Але ж агенти у нас секретні! А значить, про їхнє число повинні знати тільки вони і ніхто інший. Ми легко можемо додати модифікатор protectedдо поля agentCount, і тоді отримати його значення зможуть або об'єкти інших класів секретних агентів, або класи, які розташовані в нашому «секретному» пакеті top_secret.
public abstract class AbstractSecretAgent {

   protected static int agentCount = 0;
}
Ось для таких специфічних завдань і потрібний модифікатор protected:)

Модифікатор package visible

Далі у нас за списком йде модифікатор defaultабо, як його ще називають, package visible. Він не позначається ключовим словом, оскільки встановлений у Java за промовчанням для всіх полів та методів. Якщо написати в твоєму коді
int x = 10;
… у змінної xбуде цей package visibleдоступ. Якщо метод (або змінна) не позначені ніяким модифікатором, вважається, що вони позначені «за замовчуванням модифікатором». Змінні або методи з таким модифікатором (тобто взагалі без якогось) видно всім класам пакета, в якому вони оголошені. І лише їм. Випадки застосування обмежені, як і в модифікатора protected. Найчастіше defaultдоступ використовується в пакеті, де є якісь класи-утиліти, що не реалізують функціональність всіх інших класів у цьому пакеті. Наведемо приклад. Уяви, що у нас є пакет « services ». Усередині нього лежать різні класи, які працюють із базою даних. Наприклад, є клас UserService, який зчитує дані користувачів з БД, класCarService, що зчитує з цієї ж БД дані про автомобілі, та інші класи, кожен з яких працює зі своїм типом об'єктів та читає дані про них з бази.
package services;

public class UserService {
}

package services;

public class CarService {
}
Однак легко може статися ситуація, коли дані у базі даних лежать в одному форматі, а нам вони потрібні в іншому. Уяви, що дата народження користувача в БД зберігається у форматі TIMESTAMP WITH TIME ZONE...
2014-04-04 20:32:59.390583+02
...нам натомість потрібен найпростіший об'єкт — java.util.Date. Для цієї мети можемо створити всередині пакета servicesспеціальний клас Mapper. Він буде відповідати за конвертацію даних із бази у звичні нам Java-об'єкти. Простий допоміжний клас. Зазвичай ми створюємо всі класи як public class ClassName, але це не обов'язково. Ми можемо оголосити наш допоміжний клас просто як class Mapper. У такому разі він все одно робить свою роботу, але не видно нікому поза пакетом services!
package services;

class Mapper {
}


package services;

public class CarService {

   Mapper mapper;
}
А це, по суті, правильна логіка: навіщо комусь поза пакетом бачити допоміжний клас, який працює тільки з класами цього ж пакета?

Модифікатор

І останній за списком, але не за значущістю – модифікатор public! З ним ти познайомився в перший день навчання на JavaRush, вперше в житті запустивши public static void main(String[] args). Модифікатори доступу.  Private, protected, default, public - 4 Тепер, коли ти вивчив лекції про інтерфейси, тобі очевидно його призначення :) Адже publicстворений для того, щоб віддавати щось користувачам. Наприклад, інтерфейс програми. Допустимо, ти написав програму-перекладач, і вона вміє перекладати російську мову в англійську. Ти створив метод translate(String textInRussian), у якому реалізована необхідна логіка. Цей метод ти відзначив словом publicі тепер він стане частиною інтерфейсу:
public class Translator {

   public String translate(String textInRussian) {

       // перекладає текст з російської на англійську
   }
}
Можна пов'язати виклик цього методу з кнопкою "перекласти" на екрані програми - і все! Будь-хто може цим користуватися. Частини коду, позначені модифікатором public, призначені для кінцевого користувача. Якщо навести приклад із життя, privateце всі процеси, що відбуваються всередині телевізора, коли він працює, а publicце кнопки на пульті телевізора, за допомогою яких користувач може ним керувати. При цьому йому не потрібно знати, як влаштований телевізор і за рахунок чого він працює. Пульт - це набір publicметодів: on(), off(), nextChannel(), previousChannel(), increaseVolume(), decreaseVolume()і т.д.
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ