Найважливішим фактором об'єктно-орієнтованої розробки є відділення змінних складових від постійних.
Це особливо важливо для бібліотек. Користувач
Бажана мета може бути досягнута певними домовленостями: Наприклад, програміст бібліотеки погоджується не вилучати вже існуючі методи класу, тому що це може порушити структуру коду програміста-клієнта. У той же час зворотна проблема набагато гостріше. Наприклад, як творець бібліотеки дізнається, які з полів даних використовуються програмістом-клієнтом? Це саме можна сказати і до методів, що є тільки частиною реалізації класу, тобто не призначеним для прямого використання програмістом-клієнтом. А якщо творцеві бібліотеки знадобиться видалити стару реалізацію і замінити її новою? Зміна будь-якого з полів класу може порушити роботу коду програміста-клієнта. Виходить, у творця бібліотеки «зв'язані руки», і він взагалі нічого не має права змінювати.
Для вирішення проблеми в Java визначені специфікатор доступу (access specifiers), за допомогою яких автор бібліотеки вказує, що є програмісту-клієнту, а що ні. Рівні доступу (від повного до мінімального) задаються наступними ключовими словами: public, protected. доступ в межах пакету (не має ключового слова) і private. З попереднього абзацу може виникнути враження, що творцеві бібліотеки найкраще зберігати все якомога «секретнішу», а відкривати тільки ті методи, які, на вашу думку, повинен використовувати програміст-клієнт. І це абсолютно вірно, хоча і виглядає незвично для людей, чиї програми на інших мовах (особливо це стосується C) «звикли» до відсутності обмежень. До кінця цієї глави ви наочно переконаєтеся в корисності механізму контролю доступу в Java.
Однак концепція бібліотеки компонентів і контролю над доступом до цих компонентів - це ще не все. Залишається зрозуміти, як компоненти зв'язуються в об'єднану цільну бібліотеку. В Java це завдання вирішується ключовим словом package (пакет), і специфікатор доступу залежать від того, чи знаходяться класи в одному або в різних пакетах. Тому для початку ми розберемося, як компоненти бібліотек розміщуються в пакетах. Після цього ви зможете в повній мірі зрозуміти сенс специфікаторів доступу.
Пакет як бібліотечний модуль
Пакет містить групу класів, об'єднаних в одному просторі імен.
Наприклад, в стандартну поставку Java входить службова бібліотека, оформлена у вигляді простору імен java.util. Один з класів java.util називається ArrayList. Щоб використовувати клас у програмі, можна використовувати його повне ім'я java.util.ArrayList. Втім, повні імена занадто громіздкі, тому в програмі зручніше використовувати ключове слово import. Якщо ви збираєтеся використовувати всього один клас, його можна вказати прямо в директиві import:
Тепер до класу ArrayList можна звертатися без вказівки повного імені, але інші класи пакету java.util залишаться недоступними. Щоб імпортувати всі класи, вкажіть * замість імені класу, як це робиться майже у всіх прикладах книги:
Механізм імпортування забезпечує можливість управління просторами імен. Імена членів класів ізолюються одна від одної. Метод f () класу А не конфліктує з методом f () з таким же визначенням (списком аргументів) класу В. А як щодо імен класів? Припустимо, що клас Stack створюється на комп'ютері, де кимось іншим вже було визначено клас з ім'ям Stack. Потенційні конфлікти імен - основна причина, по якій так важливі управління просторами імен в Java і можливість створення унікальних ідентифікаторів для всіх класів.
До цього моменту більшість прикладів книги записувалися в окремих файлах і призначалися для локального використання, тому на імена пакетів можна було не звертати уваги. (В такому випадку імена класів розміщуються в «пакеті за замовчуванням».) Звичайно, це теж рішення, і такий підхід буде застосовуватися в книзі, де тільки можливо. Але, якщо ви створюєте бібліотеку або програму, яка використовує інші програми Java на цій же машині, варто подумати про запобігання конфліктів імен.
Файл з вихідним текстом на Java часто називають компільовані модулем. Ім'я кожного компилируемого модуля має завершуватися суфіксом .java. а всередині нього може перебувати відкритий (public) клас, який має те ж ім'я, що і файл (з великої літери, але без розширення .java). Будь компільований модуль може містити не більше одного відкритого класу, інакше компілятор повідомить про помилку. Решта класи модуля, якщо вони там є, приховані від навколишнього світу - вони не є відкритими (public) і вважаються «допоміжними» по відношенню до головного відкритого класу.
В результаті компіляції для кожного класу, визначеного в файлі .java. створюється клас з тим же ім'ям але з розширенням .class. Таким чином, при компіляції декількох файлів .java може з'явитися цілий ряд файлів з рас-розширенням .class. Якщо ви програмували на компільовані мови, то, напевно, звикли до того, що компілятор генерує проміжні файли (зазвичай з розширенням OBJ), які потім об'єднуються компоновщиком для отримання виконуваного файлу або бібліотеки. Java працює не так. Робоча програма являє собою набір однорідних файлів .class. які об'єднуються в пакет і стискаються в файл JAR (утилітою Javajar). Інтерпретатор Java відповідає за пошук, завантаження і інтерпретацію цих файлів.
Бібліотека також є набором файлів з класами. В кожному файлі є один рublіс -клас з будь-якою кількістю класів, які не мають специфікатор public. Якщо ви хочете оголосити, що всі ці компоненти (які зберігаються в окремих файлах .java і .class) пов'язані один з одним, скористайтеся ключовим словом package.
означає, що даний компільований модуль входить в бібліотеку з ім'ям access. Інакше кажучи, ви вказуєте, що відкритий клас в цьому модульна модулі належить імені mypackage і, якщо хтось захоче використовувати його, йому доведеться повністю записати або ім'я класу, або директиву import з access (конструкція, зазначена вище). Зауважте, що за правилами Java імена пакетів записуються тільки малими літерами.
Припустимо, файл називається MyClass.java. Він може містити один і тільки один відкритий клас (public), причому останній повинен називатися MyClass (з урахуванням регістру символів):
Якщо тепер хтось захоче використовувати MyClass або будь-які інші відкриті класи з пакета access. йому доведеться використовувати ключове слово import. щоб імена з access стали доступними. Можливий і інший варіант - записати повне ім'я класу: