You are on page 1of 61

ЛЕКЦІЯ 4.

УПРАВЛІННЯ
ДОСТУПОМ
Глибовець А.М.
ВСТУП
 Важливим фактором об’єктно-орієнтованої
розробки є відділення змінних складових від
постійних.
 Це особливо важливо для бібліотек.

 Програміст-клієнт бібліотеки залежить від


незмінності деякого аспекту коду.
 З іншого боку – створювач бібліотеки має мати змогу
змінювати і покращувати свою бібліотеку, і вони не
мають порушувати працездатність клієнтського коду.
ВСТУП
 Необхідно ввести домовленості.
 Наприклад:
 Програміст бібліотеки погоджується не видаляти методи
класу, що вже існують, бо це може порушити структуру
коду користувача.
 Але зворотна проблема гостріша. Як програміст
бібліотеки дізнається які поля використовує користувач, а
які ні?
 Те ж саме стосується і методів, що є лише частиною
реалізації класу?
 А якщо необхідно видалити стару реалізацію і замінити
на нову?
 Виходить, домовитися ми не можемо і у розробника
бібліотеки зв’язані руки …
ВСТУП
 Для вирішення цієї проблеми у Java визначені
специфікатори доступу (access specifiers), за
допомогою яких можливо показати, які частини
класу доступні користувачу, а які приховані.
 Рівні доступу задаються наступними словами:
 public
 protected
 доступ в межах пакету (не має ключового слова)
 private
ВСТУП
 Як, на вашу думку, необхідно вчинити розробнику
бібліотеки стосовно того, як використовувати
ідентифікатори?
 Може скластися уявлення, що створювачу бібліотеки
краще за все зберігати все якомога «секретніше», а
відкривати лише ті методи, що, за вашим
розумінням, мають використовуватися програмістом-
клієнтом.
 І це правильно.
ВСТУП
 Однак концепція бібліотеки компонентів все ще не
повна.
 Необхідно зрозуміти, як компоненти групуються в
бібліотеку.
 У Java ця задача вирішується з використанням
ключового слова package (пакет), і специфікатори
доступу залежать від того, знаходяться класи в
одному чи в декількох пакетах.
 Тому спочатку розберемося як компоненти бібліотек
розміщуються в пакетах.
 Після чого зрозумієте повною мірою зміст
специфікаторів доступу.
ПАКЕТ ЯК БІБЛІОТЕЧНИЙ МОДУЛЬ
ПАКЕТ ЯК БІБЛІОТЕЧНИЙ МОДУЛЬ
 Пакет – група класів, об’єднана в одному просторі імен.
 Пакет – java.util.
 Клас – java.util.ArrayList
 Використовувати довгі імена незручно, тому
використовуємо ключове слово import.
 Якщо ви хочете використати один клас з пакету, його
можна прямо вказати в директиві import
 import java.util.ArrayList;
 Тепер до класу ArrayList можна звертатися прямо за ім’ям
 Але всі інші класи пакету недоступні, тому можна
написати
 import java.util.*;
ПАКЕТ ЯК БІБЛІОТЕЧНИЙ МОДУЛЬ
 Механізм імпортування дозволяє забезпечувати
можливість управління просторами імен.
 Вирішується конфлікт імен!!!
ПАКЕТ ЯК БІБЛІОТЕЧНИЙ МОДУЛЬ
 Метод f () всередині класу A не буде конфліктувати з
методом f () який має таку ж сигнатуру (список
аргументів) в класі B.
 А як же з іменами класів?

 Уявіть, що Ви створюєте клас stack і встановлюєте на


машині, на якій уже є клас stack, написаний кимось
іншим?
 З Java в Інтернет таке цілком може статися, і ви про
це можете не дізнатися, тому що класи часто
завантажуються автоматично в процесі запуску Java-
програми.
ПАКЕТ ЯК БІБЛІОТЕЧНИЙ МОДУЛЬ
 Досі більшість ваших прикладів існували в
одиничному файлі і проектувалися для локального
використання.
 У цьому випадку клас розташовувався у «пакеті за
замовчуванням».
 Заради спрощення такий підхід ви можете
використовувати, де це можливо.
 Однак, якщо Ви плануєте створювати бібліотеки і
програми, які використовують інші програми на Java,
на тій же машині, Вам потрібно буде подумати про
запобігання конфліктів з іменами класів.
ПАКЕТ ЯК БІБЛІОТЕЧНИЙ МОДУЛЬ
 Коли Ви створюєте файл вихідного тексту в Java, він
зазвичай називається модулем компіляції (іноді модулем
трансляції).
 Кожен модуль компіляції повинен мати розширення .java,
і всередині нього може бути розташований публічний
клас, який повинен мати ім'я таке саме, як ім'я файлу (з
урахуванням регістру, але без розширення .java).
 У кожному модулі компіляції може бути тільки один
публічний клас, в іншому випадку компілятор буде
незадоволений .
 Інші класи у цьому модулі компіляції, якщо вони є,
приховані від зовнішнього, і являють собою класи
"підтримки" для головного публічного класу.
ПАКЕТ ЯК БІБЛІОТЕЧНИЙ МОДУЛЬ
 Коли Ви компілюєте файл .java Ви отримуєте
вихідний файл з таким самим ім'ям і
розширенням .class.
 Таким чином, з декількох .java файлів Ви отримуєте
декілька .class файлів.
 Працююча програма - це набір .class файлів, які
можуть бути зібрані в пакет і запаковані в JAR файл
(за допомогою Java архіватора jar).
 А інтерпретатор Java здатний знаходити,
завантажувати та інтерпретувати ці файли.
ПАКЕТ ЯК БІБЛІОТЕЧНИЙ МОДУЛЬ
 Бібліотека - також набір .class файлів.
 Кожен файл містить один публічний клас (Вас не
примушують мати публічний клас, але це типова
ситуація), так що для кожного файлу є один
компонент.
 Якщо Ви хочете, щоб всі ці компоненти зберігалися
разом, Ви використовуєте ключове слово package.
ПАКЕТ ЯК БІБЛІОТЕЧНИЙ МОДУЛЬ
 Директива package має бути в першій
незакоментованій стрічці файлу.
 Така команда:
 package access;
 означає, що даний компільований модуль входить в
бібліотеку з ім’ям access.
ПАКЕТ ЯК БІБЛІОТЕЧНИЙ МОДУЛЬ
 Наприклад, припустимо, що ім'я файлу -
MyClass.java.
 Це означає, що може бути тільки один публічний
клас в цьому файлі, та ім'я цього класу має бути -
MyClass (враховуючи регістри):
 package mypackage;
 public class MyClass {
 // . . .
ПАКЕТ ЯК БІБЛІОТЕЧНИЙ МОДУЛЬ
 Тепер, якщо хтось захоче використовувати клас
MyClass або будь-який інший публічний клас з
пакету mypackage, йому потрібно буде
використовувати ключове слово import щоб зробити
доступними імена з пакету mypackage.
 Існує також альтернатива - використання імен з
префіксами:
 mypackage.MyClass m = new mypackage.MyClass();
 Але ключове слово import може це сильно спростити:
 import mypackage.*;
 //
...
 MyClass m = new MyClass();
ПАКЕТ ЯК БІБЛІОТЕЧНИЙ МОДУЛЬ
 За допомогою ключових слів package і import, Ви
можете, як розробник бібліотеки, розділяти
глобальний простір імен і, в результаті, виключити
конфлікт імен, незалежно від того, скільки людей
підключаються до Інтернет і починають писати класи
на Java.
 Розглянемо приклад:
 ua.com.glybovets.examples.lecture4.access.MyClass
 ua.com.glybovets.examples. lecture4. QualifiedMyClass

 ua.com.glybovets.examples. lecture4.ImportedMyClass
СТВОРЕННЯ УНІКАЛЬНИХ ІМЕН
ПАКЕТІВ
СТВОРЕННЯ УНІКАЛЬНИХ ІМЕН
ПАКЕТІВ
 Ви можете помітити, що оскільки пакет насправді
ніколи не «пакується» в один файл, він може
складатися з безлічі файлів .class, що може призвести
до безладу.
 Для вирішення цієї проблеми логічно необхідно
розмістити всі файли .class конкретного пакету в
одному каталозі (використати ієрархічну структуру
файлової системи).
СТВОРЕННЯ УНІКАЛЬНИХ ІМЕН
ПАКЕТІВ
 Розміщення файлів пакету в окремому каталозі
вирішує дві інші задачі:
 Створенняунікальних імен пакетів
 Пошук класів, загублених в «хащах» структури каталогів.
 Проблема вирішується кодуванням шляху файлу в
імені пакету.
 За загальноприйнятою практикою перша частина
імені пакету має складатися з перевернутого
доменного імені розробника класу.
 Доменні імена Інтернет – унікальні, це вирішує
проблему унікальності пакетів.
СТВОРЕННЯ УНІКАЛЬНИХ ІМЕН
ПАКЕТІВ
 Інтерпретатор Java діє в такому порядку.
 Спочатку він шукає змінну середовища з ім'ям CLASSPATH
(вона встановлюється в операційній системі).
 CLASSPATH містить один або більше каталогів, які
використовуються як кореневі для пошуку .class файлів.
 Починаючи з цього кореневого каталогу, інтерпретатор бере ім'я
пакету і замінює кожну точку на косу риску для створення імені
шляху від кореня в CLASSPATH (так, наприклад, package
foo.bar.baz перетвориться на foo\bar\baz або foo/bar/baz (може
бути щось інше, в залежності від Вашої операційної системи).
 Потім це додається до різних елементів змінної CLASSPATH.
 Він також здійснює пошук у стандартних каталогах, де
розташовується сам інтерпретатор.
СТВОРЕННЯ УНІКАЛЬНИХ ІМЕН
ПАКЕТІВ
 Щоб зрозуміти усе вище сказане, розглянемо моє
доменне ім’я glybovets.com.ua
 Перевертаємо його і отримуємо унікальне глобальне
ім’я – ua.com.glybovets для моїх класів.
 Тепер якщо я хочу створити бібліотеку з ім’ям
practice1 у мене вийде наступне ім’я пакету:
 package ua.com.glybovets.practice1
КОНФЛІКТИ ІМЕН
КОНФЛІКТИ ІМЕН
 Що відбувається при імпортуванні конструкцією *
двох бібліотек, що мають в своєму складі ідентичні
імена?
 Приклад:
 import ua.com.glybovets.utils.*;
 import java.util.*;
 І в моїй бібліотеці присутній власний клас Vector, але
і в бібліотеці java.util також присутній клас Vector.
 Це може призвести до потенційного конфлікту.
 Але поки ви не почнете писати код, що викликає
конфлікти, все буде нормально працювати (і це добре
…).
КОНФЛІКТИ ІМЕН
 Конфлікт дійсно відбудеться при спробі створити
Vector:
 Vector v = new Vector();
 Якого з класів Vector стосується ця команда?
 Цього не знає ні компілятор ні читач програми …

 Тому компілятор видасть повідомлення про помилку,


з проханням явно вказати необхідне ім’я.
 Наприклад:
 java.util.Vector v = new java.util.Vector();
 Розглянемо приклад AccessConflict
БІБЛІОТЕКИ КОРИСТУВАЧА
БІБЛІОТЕКИ КОРИСТУВАЧА
 Тепер ви можете створювати власні бібліотеки
корисних утиліт і потім використовувати у своїх
програмах.
БІБЛІОТЕКИ КОРИСТУВАЧА
 Попередження!
 Пам’ятайте, що створення пакету завжди неявно
пов’язано з визначенням структури каталогів.
 Пакет має міститися в однойменному каталозі.

 Давайте поглянемо на структуру каталогів пакету


ua.com.glybovets.*;
СПЕЦИФІКАТОРИ ДОСТУПУ JAVA
СПЕЦИФІКАТОРИ ДОСТУПУ JAVA
 У Java специфікатори доступу public, protected і
private розташовуються перед визначенням членів
класів – як полів так і методів.
 Якщо специфікатор доступу не вказаний,
використовується «пакетний» рівень доступу.
 Тому ЗАВЖДИ існує специфікація доступу.

 Розглянемо конкретніше кожний з них.


ДОСТУП В МЕЖАХ ПАКЕТУ
 Раніше ми в більшості випадків не писали
специфікатори доступу.
 Доступ за замовчуванням не має ключового слова,
але часто його називають доступом у межах пакету
(package access).
 Це значить, що клас доступний для всіх інших класів
поточного пакету, але для класів за межами пакету
він недоступний (сприймається як приватний
(private)).
ДОСТУП В МЕЖАХ ПАКЕТУ
 Доступ в межах пакету дозволяє групувати
взаємопов’язані класи в одному пакеті, щоб вони
могли легко взаємодіяти один з одним.
 Розміщуючи класи в одному пакеті, ви берете код
пакету під повний контроль.
 Таким чином тільки код, що належить вам, буде мати
пакетний доступ до інших написаних вами класів – і
це логічно.
ДОСТУП В МЕЖАХ ПАКЕТУ
 Клас сам визначає, кому дозволений доступ до його
членів.
 Не існує чарівного способу “потрапити” до нього в
середину
 Код з іншого пакету не може просто так звернутися і
отримати доступ
ДОСТУП В МЕЖАХ ПАКЕТУ
 Отримати доступ можна лише декількома законними
способами:
 Оголосити клас відкритим (public)
 Зробити клас доступним в межах пакету і усі інші класи
розмістити в цьому ж пакеті
 Похідний клас може отримати доступ до захищених
(protected) і public полів і методів батьківського класу, але
не до private.
 Надати методи доступу, тобто методи для читання і
модифікації
PUBLIC
 При використанні ключового слова public ви
фактично оголошуєте, що наступне за ним
оголошення класу, методу, поля доступно для всіх і
перед усім для програмістів-клієнтів
 Розглянемо приклад
 ua.com.glybovets.lecture4.access.Student
 ua.com.glybovets.lecture4.University
ПАКЕТ ПО ЗАМОВЧАННЮ
 ua.com.glybovets.lecture4.University2
 ua.com.glybovets.lecture4.Student
PRIVATE
 Ключове слово private означає, що доступ до члена
класу не надається нікому, крім методів цього класу.
 Інші класи того ж пакету так само не можуть
звертатися до private-членів.
 На перший погляд ви начебто ізолюєте компонент від
самого себе …
 Але не забувайте, що пакет можуть розроблювати
ціла група розробників і в цьому випадку private
дозволяє працювати (змінювати, доповнювати …) з
членами класу, незважаючи на інших розробників
PRIVATE
 У більшості випадків доступу в межах пакету може
вистачити.
 Тому public використовується тоді, коли ви хочете
зробити якісь члени класу доступними для
програміста-клієнта.
 Може здатися, що private використовується рідко, або
майже ніколи.
 Однак осмислене використання private особливо
важливе в умовах багатопотокового програмування.
PRIVATE
 Розглянемо приклад
 Sandwich
 Bread
PRIVATE
 Усі допоміжні методи класів необхідно оголошувати
як private, щоб убезпечитися від їх випадкового
виклику в пакеті.
 Те ж саме правильно і стосовно полів класу.
PROTECTED
 Щ б зрозуміти зміст специфікатора доступу protected,
необхідно трошки забігти наперед.
 Ключове слово protected тісно пов’язане з поняттям
наслідування, завдяки якому до вже створеного класу
(базового) додаються нові члени, при чому вихідна
реалізація не змінюється.
 Так само можна змінювати поведінку членів, які вже
існують.
PROTECTED
 Для створення нового класу на основі вже створеного
використовується ключове слово extends:
 Class Foo extends Bar{…
 Інша частина реалізації виглядає як і завжди.
PROTECTED
 Якщо при створенні нового пакету використовується
наслідування від класу, що знаходиться в іншому
пакеті, новий клас отримує доступ тільки до
відкритих (public) членів з вихідного пакету.
 Для доступу зсередини пакету, отримується доступ
до всіх членів з ідентифікаторами доступу public і за
замовчуванням.
PROTECTED
 Інколи розробнику базового класу необхідно надати
доступ до конкретного методу похідним класам, але
закрити його від усіх інших.
 Саме з цією метою використовується ключове слово
protected
 Специфікатор protected також надає доступ у межах
пакету – тобто члени з цим специфікатором доступу
доступні для інших класів з того ж самого пакету
ІНТЕРФЕЙС І РЕАЛІЗАЦІЯ
ІНТЕРФЕЙС І РЕАЛІЗАЦІЯ
 Контроль над доступом часто називають
приховуванням реалізації.
 Розміщення даних і методів в класи в комбінації з
приховуванням реалізації часто називають
інкапсуляцією.
ІНТЕРФЕЙС І РЕАЛІЗАЦІЯ
 В результаті з’являється тип даних, що володіє
характеристиками і поведінкою.
 Доступ до типів даних обмежується з двох причин:
 Щоб програміст клієнт знав, що він може
використовувати, а що ні
 Ви можете вбудувати в структуру реалізації свої
внутрішні механізми, не думаючи над тим, що
програмісти-клієнти випадково використають їх як
інтерфейси
 Це підводить нас до другої причини розділення
інтерфейсу і реалізації
ІНТЕРФЕЙС І РЕАЛІЗАЦІЯ
 Якщо у програмі використана певна структура, але
програмісти-клієнти не можуть отримати доступ до її
членів, крім відправлення повідомлень public-
інтерфейсу, ви можете змінювати все, що не
оголошено як public, не порушуючи працездатності
змін клієнтського коду.
ІНТЕРФЕЙС І РЕАЛІЗАЦІЯ
 Для більшої ясності при написанні класів можна
використовувати такий стиль:
 Спочатку записуємо відкриті члени (public)
 Потім йдуть захищені члени (protected)
 Потім з доступом в середині пакету
 І в кінці закриті члени (private)

 Приклад:
 ua.com.glybovets.lecture4.OrganizedByAccess
ІНТЕРФЕЙС І РЕАЛІЗАЦІЯ
 Такий підхід лиш частково спрощує читання коду,
оскільки інтерфейс і реалізація все ще розміщуються
поруч.
 Інакше кажучи, ви все ще бачите вихідний код –
реалізацію – оскільки вона записана прямо в класі.
ДОСТУП ДО КЛАСІВ
 У Java за допомогою специфікаторів доступу можна
також вказати, які з класів всередині бібліотеки
будуть доступні для її користувачів.
 Якщо ви хочете, щоб клас був доступний
користувачу-клієнту, то додаєте ключове слово public
до всього класу.
 При цьому ви керуєте навіть самою можливістю
створювати об’єкти даного класу програмістом-
клієнтом.
 public class Widget{…
ДОСТУП ДО КЛАСІВ
 Діють наступні обмеження:
У кожному модулі, що компілюється, може існувати
тільки один відкритий (public) клас.
 Ім’я відкритого класу має збігатися з іменем файлу, в
якому міститься модуль, що компілюється.
 Модуль, що компілюється, може взагалі не містити
відкритих класів (хоча це не типово).
ДОСТУП ДО КЛАСІВ
 Класи не можна оголосити як private або protected.
 Розглянемо приклад:
 ua.com.glybovets.lecture4.Lesson;
ВИСНОВКИ
ВИСНОВКИ
 У будь-яких стосунках важливо встановити
обмеження, які будуть підтримуватися усіма
сторонами.
 При створенні бібліотеки ви встановлюєте стосунки з
користувачами бібліотеки, що створюють програми
або бібліотеки більш високого рівня.
ВИСНОВКИ
 Якщо програмісти-клієнти залишені на самоті і не
обмежені ніякими правилами, вони можуть робити
все, що їм заманеться, з будь-якими членами класів –
навіть тими, доступ до яких вам хотілося б
обмежити.
 Усі деталі реалізації відкриті зовнішньому світові.

 У цій лекції ми розглянули процес побудови


бібліотек з класів.
ВИСНОВКИ
 За оцінками проекти мовою С починають
“розсипатися” приблизно тоді, коли код досягає
об’єму 50-100 Кбайт, оскільки С має “єдиний простір
імен”, у системі виникають конфлікти імен, що
створює масу проблем.
 У Java ключове слово package, схема іменування
пакетів і ключове слово import забезпечують повний
контроль над іменами, тож конфлікту імен легко
уникнути.
ВИСНОВКИ
 Існує дві причини для обмеження доступу до членів
класу.
 Перша – попередження використання клієнтами
внутрішньої реалізації класу, що не входить у
зовнішній інтерфейс.
 Друга – можливість змінювати внутрішню
реалізацію, не зачіпаючи програмістів-клієнтів.
ВИСНОВКИ
 Відкритий інтерфейс – це те, що фактично бачить
його користувач, тому дуже важливо “довести до
розуму” саме цю, найважливішу, частину класу в
процесі аналізу і розробки.
 Навіть якщо ідеальний інтерфейс не вдалося
побудувати з першої спроби, ви можете додати в
нього нові методи – без видалення тих, що вже
існують.
ДЯКУЮ ЗА УВАГУ

You might also like