Інкапсуляція даних в класі. Управління доступом в Java. Модифікатори доступу private, protected, public
Зміст
- 1. Що означає інкапсуляція в класі?
- 2. Які існують категорії доступності членів даних класу в мові Java?
- 3. Які переваги дає використання механізму інкапсуляції в класі?
- 4. Які модифікатори доступу застосовуються до даних та методів класу?
- 5. Яка загальна форма оголошення елементу класу з заданим модифікатором доступу?
- 6. Доступ до елементів класу, які оголошені з модифікатором доступу private. Приклад
- 7. Доступ до елементів класу, які оголошені з модифікатором доступу public. Приклади
- 8. Доступ до елементів класу, які оголошені з модифікатором доступу protected. Приклади
- 9. Особливості доступу до елементів класу у випадку відсутності модифікатора доступу. Приклади
- 10. Який тип доступу мають члени класу за замовчуванням?
- 11. Чи можна оголошувати конструктор класу з модифікатором доступу private?
- Зв’язані теми
Пошук на інших ресурсах:
1. Що означає інкапсуляція в класі?
Інкапсуляція в класі означає надання відповідного доступу до членів класу з допомогою спеціальних модифікаторів доступу: private, protected, public. Доступ можна задавати як до даних, так і до методів.
⇑
2. Які існують категорії доступності членів даних класу в мові Java?
У мові Java виділяються 4 категорії доступності:
- похідні класи (підкласи) в одному пакеті;
- класи в одному пакеті, які не є похідними;
- похідні класи (підкласи) в різних пакетах;
- класи, які знаходяться в різних пакетах і не є похідними (не є підкласами).
⇑
3. Які переваги дає використання механізму інкапсуляції в класі?
Інкапсуляція даних у класі дає наступні переваги:
- якщо дані класу є прихованими, то це убезпечує від зловживань чи випадкового доступу до них. Доступ до даних забезпечується з допомогою спеціально розроблених методів класу;
- якщо дані (методи) класу є прихованими, то вони представляють свого роду “чорний ящик”. Взаємодія з даними забезпечується через відповідні методи класу;
- гнучкість в наданні доступу до різних видів даних класу з допомогою відповідних модифікаторів;
- у методах доступу до прихованих даних класу можна робити відповідні перевірки на коректність.
⇑
4. Які модифікатори доступу застосовуються до даних та методів класу?
Для управління доступом до даних та методів класу, у Java використовуються наступні модифікатори доступу:
- private. У цьому випадку дані (методи) є прихованими. Доступ до таких даних мають тільки методи класу. З екземпляру (об’єкту) класу елементи позначені як private є недоступні;
- public. Якщо член класу оголошений з модифікатором доступу public, то цей член класу є доступний з будь-якого коду даного пакету та за межами пакету (для усіх методів усіх класів);
- protected. Цей модифікатор використовується у випадку, якщо потрібно, щоб елемент класу був доступний за межами поточного пакету, але тільки класам, безпосередньо похідним (успадкованим) від даного класу.
Також елементи класу можуть бути оголошені без модифікатора доступу.
⇑
5. Яка загальна форма оголошення елементу класу з заданим модифікатором доступу?
Модифікатор доступу до конкретного члена даних чи методу встановлюється перед його оголошенням.
Загальна форма класу, в якому оголошуються один член даних класу та один метод наступна
class ClassName { // оголошення члена даних класу access_modifier type variable; // оголошення методу в класі access_modifier return_type MethodName(parameters) { // тіло методу // ... } }
де
- ClassName – ім’я оголошуваного класу;
- access_modifier – один з модифікаторів доступу private, public, protected;
- type – тип члена даних класу з іменем variable;
- variable – член даних класу, який оголошений з типом type;
- return_type – тип, який повертає метод класу з іменем MethodName();
- parameters – параметри, які отримує метод MethodName().
⇑
6. Доступ до елементів класу, які оголошені з модифікатором доступу private. Приклад
Елементи класу, які оголошені з модифікатором доступу private, є прихованими. До них мають доступ тільки методи даного класу. З усіх інших частин програмного коду до private-членів класу немає доступу.
Такий спосіб приховування даних в класі є ефективним у випадках, якщо потрібно:
- приховати деталі організації структур даних та реалізації даного класу;
- уникнути можливі випадкові зміни даних в екземплярі класу;
- забезпечити зручність доступу до даних в класі з допомогою спеціально розроблених методів. Тут мається наувазі розробка методів у класі які забезепечують читання/запис даних класу. Ці методи можуть включати відповідні перевірки на коректність при зміні даних в класі;
- уникнути можливі зловживання даними в класі що може призвести до виникнення важковловимих помилок у програмі.
Приклад. Демонструється приклад доступу до private-змінної класу з допомогою методів доступу.
Оголошується клас, що реалізує день тижня. У класі оголошується прихований (private) член даних класу з іменем value. Для доступу до value у класі використовуються:
- конструктор DayWeek(), який ініціалізує значення value=1. Конструктор оголошений без модифікатора. Це означає, що в межах пакету він має тип доступу public;
- метод Get(), який повертає значення value. Оскільки метод оголошений в класі DayWeek, то в тілі методу є доступ до змінної value;
- метод Set(), який встановлює нове значення value. Метод також оголошений в класі, тому має доступ до value. У методі здійснюється перевірка на коректність значення value в межах 1..7. Якщо задати інше значення, то значення value не зміниться;
- метод GetName(), який повертає назву дня тижня в залежності від значення value.
Реалізація класу DayWeek наступна
// клас, що реалізує день тижня class DayWeek { private int value; // прихована змінна класу // конструктор класу, ініціалізує змінну value DayWeek() { value = 1; // за замовчуванням - "Monday" } // методи доступу // метод, що повертає дані в класі public int Get() { return value; } // метод, що встановлює новий день тижня public void Set(int _value) { // у методі виконується перевірка на коректність значення _value if ((_value>=1)&&(_value<=7)) value = _value; } // додатковий метод // повертає назву дня тижня, якому відповідає value public String GetName() { String day = "Monday"; switch (value) { case 2: day = "Tuesday"; break; case 3: day = "Wednesday"; break; case 4: day = "Thursday"; break; case 5: day = "Friday"; break; case 6: day = "Saturday"; break; case 7: day = "Sunday"; break; } return day; } }
Використати такий клас в іншому коді (методі) можна, наприклад, наступним чином
public class HiddenData { public static void main(String[] args) { // доступ до private-члена даних класу DayWeek dw = new DayWeek(); int Day; String strDay; Day = dw.Get(); // Day = 1 strDay = dw.GetName(); // strDay = "Monday" System.out.println("Day = " + Day); System.out.println("strDay = " + strDay); // встановити нове значення дня dw.Set(3); // перевірка Day = dw.Get(); // Day = 3 strDay = dw.GetName(); // strDay = "Wednesday" System.out.println("Day = " + Day); System.out.println("strDay = " + strDay); } }
Результат виконання вищенаведеної програми
Day = 1 strDay = Monday Day = 3 strDay = Wednesday
⇑
7. Доступ до елементів класу, які оголошені з модифікатором доступу public. Приклади
До елементів класу, які оголошені з модифікатором доступу public є доступ з будь-якого програмного коду пакету, в якому оголошений даний клас.
Якщо потрібно мати доступ до public-елементів класу з інших пакетів, то цей клас також має бути оголошений з модифікатором public. Більш детально про особливості доступу до public-класів в пакетах описується в темі:
⇑
7.1. Приклад доступу до public-елементу класу в межах пакету
Задано клас A з членом даних value, який оголошений з модифікатором public. Нижче продемонстровано три можливі способи доступу до public-члена даних value:
- з поточного класу A;
- з класу B, який оголошений у даному пакеті;
- з класу C, який оголошений у даному пакеті та є похідним від класу A.
// деякий клас class A { public int value; // змінна, оголошена з модифікатором public // доступ з методу поточного класу void methodA() { value = 5; } } class B { // доступ з методу іншого класу даного пакету void methodB() { A objA = new A(); objA.value = 10; } } // клас C успадковує клас A class C extends A { // доступ з методу похідного класу void methodC() { value = 30; } }
⇑
7.2. Приклад доступу до public-елемента класу з іншого пакету
Щоб доступитись до public-елемента класу з іншого пакету цей клас має бути також оголошений як public.
Нехай в пакеті Package1 задано клас з іменем DemoPackage1. У класі оголошується public-змінна value.
// модифікатор доступу public, пакет Package1 package Package1; // Пакет Package1 // public-клас DemoPackage1 public class DemoPackage1 { public int value; // ця змінна є доступна за межами пакету public static void main(String[] args) { } }
Тоді, доступ до з іншого пакету Package2 до змінної value може бути:
- з допомогою використання екземпляру (об’єкту) класу Package1.DemoPackage1;
- з допомогою класу, який є похідним від класу Package1.DemoPackage1.
// Пакет Package2 package Package2; // підключення класу DemoPackage1 з пакету Package1. import Package1.DemoPackage1; // деякий клас в пакеті Package2 public class DemoPackage2 { public static void main(String[] args) { // створення екземпляру класу DemoPackage1, // який розміщується в пакеті Package1 - дозволено Package1.DemoPackage1 dp1 = new Package1.DemoPackage1(); // доступ до public-змінної класу з іншого пакету, який оголошений як public dp1.value = 30; } } // клас, який успадковує (розширює) клас DemoPackage1 з пакету Package1 class DemoPackage3 extends DemoPackage1 { // метод, який має доступ до Package1.DemoPackage1.value void IncValue(int _delta) { value = value + _delta; // збільшити value на величину delta } }
Слід зауважити, якщо в пакеті Package2 розміщується директива
import Package1.DemoPackage1;
то до класу DemoPackage1 з пакету Package1 можна звертатись будь-яким з двох способів:
- з врахуванням імені пакету: Package1.DemoPackage1;
- без використання імені пакету перед іменем класу: DemoPackage1.
⇑
8. Доступ до елементів класу, які оголошені з модифікатором доступу protected. Приклади
Розглядають два випадки доступу до protected-елемента класу:
- в межах пакету, в якому клас з даним protected-елементом оголошений (в поточному пакеті);
- з іншого пакету.
Якщо в деякому пакеті елемент класу оголошений з ключовим словом protected, то:
- в поточному пакеті цей елемент є видимий з будь-якого коду;
- в іншому пакеті цей елемент є видимий тільки у похідних класах.
Доведемо це на прикладах.
⇑
8.1. Приклад доступу до protected-члена даних класу в межах пакету
Задано клас A, в якому є оголошений protected-член даних value. У даному пакеті до елементу класу value можна мати доступ наступними способами:
- з поточного класу A;
- з класу B, який оголошений у даному пакеті;
- з класу C, який оголошений у даному пакеті та є похідним від класу A.
// модифікатор доступу protected, пакет Package1 package Package1; // деякий клас class A { protected int value; // змінна, оголошена з модифікатором protected // доступ з методу поточного класу void methodA() { value = 5; } } class B { // доступ з методу іншого класу даного пакету void methodB() { A objA = new A(); objA.value = 10; } } // клас C успадковує клас A class C extends A { // доступ з методу похідного класу void methodC() { value = 30; } }
З вищенаведеного коду можна зробити наступний висновок:
- в межах пакету доступ до protected-елементів класу такий самий як і до public-елементів класу.
⇑
8.2. Приклад доступу до protected-члена даних класу з іншого пакету
Для того, щоб protected-елемент класу був доступний за межами даного пакету, цей клас має бути оголошений з модифікатором public.
Щоб доступитись до protected-елементу класу з класів інших пакетів потрібно, щоб ці класи були похідними від даного класу.
Розглянемо це на прикладі.
Нехай задано пакет з іменем Package1. У цьому пакеті реалізовано клас DemoPackage1, в якому оголошується protected-змінна value.
// модифікатор доступу protected, // пакет Package1 package Package1; // public-клас DemoPackage1 public class DemoPackage1 { // за межами пакету ця змінна є доступна тільки у похідних класах protected int value; public static void main(String[] args) { } }
У нижченаведеному коді продемонстровано доступ з іншого пакету Package2 до protected-змінної value класу DemoPackage1 (пакет Package1).
// Пакет Package2 package Package2; // підключення класу DemoPackage1 з пакету Package1. import Package1.DemoPackage1; // деякий клас в пакеті Package2 public class DemoPackage2 { public static void main(String[] args) { // створення екземпляру класу DemoPackage1, // який розміщується в пакеті Package1 - дозволено Package1.DemoPackage1 dp1 = new Package1.DemoPackage1(); // доступ до protected-змінної класу з іншого пакету // dp1.value = 30; - ЗАБОРОНЕНО, помилка } } // клас, який успадковує (розширює) клас DemoPackage1 з пакету Package1 // цей клас має доступ до protected-змінної value class DemoPackage3 extends DemoPackage1 { // метод, який має доступ до Package1.DemoPackage1.value void IncValue(int _delta) { value = value + _delta; // доступ ДОЗВОЛЕНО } }
Якщо зняти коментар з рядка
dp1.value = 30;
то компілятор видасть помилку
The field DemoPackage1.value is not visible
⇑
9. Особливості доступу до елементів класу у випадку відсутності модифікатора доступу. Приклади
При оголошенні, модифікатор доступу до членів класу може бути відсутній. У цьому випадку до члена класу мають доступ:
- методи цього класу;
- методи похідного підкласу, який оголошений в цьому самому пакеті;
- методи будь-якого класу, який розміщений в цьому самому пакеті.
Заборонено доступ з інших пакетів до елементів класу, оголошених без модифікатора доступу.
Приклад 1. У прикладі демонструється доступ до змінної value класу A з методів інших класів. Змінна value класу A оголошена без модифікатора доступу.
// пакет Package1 // модифікатор доступу відсутній package Package1; class A { int value; // змінна, оголошена без модифікатора доступу // доступ з методу поточного класу void methodA() { value = 5; // доступ дозволено } } class B { // доступ з методу іншого класу даного пакету void methodB() { A objA = new A(); // екземпляр класу A objA.value = 10; // доступ дозволено } } class C extends A { // доступ з методу похідного класу void methodC() { value = 30; // доступ дозволено } }
Приклад 2. Демонстрація заборони доступу з іншого пакету до змінної value класу DemoPackage1, яка оголошена без модифікатора доступу.
Задано два пакети з іменами Package1 та Package2. У пакеті Package1 оголошується public-клас з іменем DemoPackage1. У цьому класі оголошується змінна value без модифікатора доступу.
Текст пакету Package1 наступний:
// Пакет Package1 // клас DemoPackage1 public class DemoPackage1 { int value; // ця змінна є доступна тільки в цьому пакеті public static void main(String[] args) { } }
В іншому пакеті Package2 оголошується клас DemoPackage2 та директива import, яка підключає пакет Package1.
// Пакет Package2 package Package2; // підключення класу DemoPackage1 з пакету Package1. import Package1.DemoPackage1; // деякий клас в пакеті Package2 public class DemoPackage2 { public static void main(String[] args) { // створення екземпляру класу DemoPackage1, // який розміщується в пакеті Package1 - дозволено Package1.DemoPackage1 dp1 = new Package1.DemoPackage1(); // неможливо доступитись до змінної іншого пакету, // яка оголошена без модифікатора // dp1.value = 10; - помилка, доступ до змінної dp1.value ЗАБОРОНЕНО! } }
Як видно з прикладу, спроба викликати рядок
dp1.value = 10;
з пакету Package2 викличе помилку компілятора з наступним повідомленням
The field DemoPackage1.value is not visible
Це означає, що поле value класу DemoPackage1 є невидимим.
⇑
10. Який тип доступу мають члени класу за замовчуванням?
Перед оголошенням змінної, екземпляру чи методу в класі не обов’язково вказувати модифікатор доступу. Якщо модифікатор доступу відсутній перед оголошенням членів класу, то приймається доступ за замовчуванням. Для членів класу в Java встановлено загальнодоступний (public) доступ за замовчуванням.
⇑
11. Чи можна оголошувати конструктор класу з модифікатором доступу private?
Так можна. Такий конструктор ніколи не буде викликаний з за меж класу, тобто з екземпляру (об’єкту) класу. Але такий конструктор може бути використаний у методах, що оголошуються в самому класі при створенні екземплярів цього класу.
Наприклад. Нехай задано клас з іменем CData. У класі оголошуються:
- конструктор без параметрів з модифікатором доступу public;
- прихований (private) конструктор з одним параметром. Цей конструктор буде використовуватись у методі UseCData(), який оголошений у цьому ж класі;
- метод CData, який використовує прихований (private) конструктор CData() з одним параметром.
Текст оголошення та використання класу має вигляд:
// клас, що містить прихований конструктор class CData { int d; // член даних d має доступ public за замовчуванням // public-конструктор, видимий за межами класу CData() { d = 0; } // прихований конструктор, видимий тільки в межах класу private CData(int _d) { d = _d; } // метод, що використовує прихований (private) конструктор класу public void UseCData(int _d) { CData DD = new CData(_d); // використати private-конструктор класу System.out.println("DD = " + DD.d); } } public class TestClass { public static void main(String[] args) { // створити екземпляр класу CData CData D1 = new CData(); // виклик public-конструктора без параметру // Заборонено викликати private-конструктор класу CData //CData D2 = new CData(2); // доступ до члена даних d D1.d = 30; System.out.println("D1.d = " + D1.d); D1.UseCData(55); // вивести на екран DD=55 } }
Як видно з оголошення класу, у методі UseCData() викликається прихований (private) конструктор з одним параметром
... CData DD = new CData(_d); // використати private-конструктор класу ...
У результаті виконання вищенаведеного коду, на екран буде виведено:
D1.d = 30 DD = 55
⇑
Зв’язані теми
- Застосування класів у програмах на Java. Визначення класу та об’єкту класу. Приклади
- Пакети. Використання пакетів у Java. Директиви import та package. Компільовані модулі (.java). Проміжні .class файли. Використання стандартних бібліотек Java
- Управління доступом до класів у пакетах. Пакетний рівень доступу до класу. Загальнодоступний (public) рівень доступу до класу
⇑