русс | укр

Мови програмуванняВідео уроки php mysqlПаскальСіАсемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование


Linux Unix Алгоритмічні мови Архітектура мікроконтролерів Введення в розробку розподілених інформаційних систем Дискретна математика Інформаційне обслуговування користувачів Інформація та моделювання в управлінні виробництвом Комп'ютерна графіка Лекції


Тема 9 Імена, пакети. Оголошення класів


Дата додавання: 2014-05-29; переглядів: 1197.


План

1 Імена. Прості й складені імена. Елементи

2 Облалсть видимості

3 Пакети

4 Оголошення класу

5 Іморт-вирази

6 Унікальність імен пакетів

7 Призначення модифікаторів доступу

8 Тіло класу

 

1 Імена. Прості й складені імена. Елементи

Імена бувають простими (simple), що складаються з одного ідентифікатора (вони визначаються під час оголошення) і складними (qualified), що складаються з послідовності ідентифікаторів, розділених крапкою. Для пояснення цих термінів необхідно розглянути ще одне поняття.

У пакетів і вказівних типів (класів, інтерфейсів, масивів) є елементи (members). Доступ до елементів здійснюється за допомогою виразу, що складається з імен, наприклад, пакету й класу, розділених крапкою.

Далі класи та інтерфейси будуть називатися об'єднуючим терміном тип (type).

Елементами пакету є класи та інтерфейси, що містяться в ньому, а також вкладені пакети. Щоб отримати складене ім'я пакету, необхідно до повного імені пакету, у якому він розташовується, додати крапку, а потім його власне просте ім'я. Наприклад, складене ім'я основного пакету мови Java - java.lang (тобто просте ім'я цього пакету lang, і він знаходиться в загальному пакеті java).

Просте ім'я класів та інтерфейсів дається при оголошенні, наприклад, Object, String, Point. Щоб отримати складене ім'я таких типів, треба до складеного імені пакету, у якому знаходиться тип, через крапку додати просте ім'я типу. Наприклад, java.lang.Object, java.lang.reflect.Method або com.myfirm.MainClass. Для вказівних типів елементами є поля й методи, а також внутрішні типи (класи та інтерфейси). Елементи можуть бути як безпосередньо оголошені в класі, так і отримані в спадок від батьківських класів і інтерфейсів, якщо такі є. Просте ім'я елементів також дається при ініціалізації. Наприклад, toString (), PI, InnerClass. Складене ім'я виходить шляхом об'єднання простого чи складеного імені типу, або змінною об'єктного типу з ім'ям елемента. Наприклад, ref.toString (), java.lang.Math.PI, OuterClass.InnerClass. Інші звернення до елементів вказівних типів вже неодноразово застосовувалися в попередніх розділах.

 

2 Область видимості

Щоб не змушувати програмістів, які працюють разом над різними класами однієї системи, координувати імена, які вони дають різним конструкціям мови, у кожного імені є область видимості (scope). Якщо звернення, наприклад, до поля, йде з частини коду, що потрапляє в область видимості його імені, то можна користуватися простим ім'ям, якщо ні - необхідно застосовувати складене.

 

 

3 Пакети

Програма на Java являє собою набір пакетів (packages). Кожен пакет може включати вкладені пакети, тобто смороду утворюють ієрархічну систему.

Крім того, пакети можуть містити класи та інтерфейси й таким чином групують типи. Це необхідно відразу для кількох цілей. По-перше, чисто фізично неможливо працювати з великою кількістю класів, якщо вони «звалені в купу». По-друге, модульна декомпозиція полегшує проектування системи. До того ж, як буде показано нижче, існує спеціальний рівень доступу, що дозволяє типам з одному пакету більш тісно взаємодіяти один з одним, ніж з класами інших пакетів. Таким чином, за допомогою пакетів проводиться логічне групування типів. З ООП відомо, що велика зв'язність системи, тобто середня кількість класів, з якими взаємодіє кожний клас, помітно ускладнює розвиток і підтримку такої системи. Використовуючи пакети, набагато простіше організувати ефективну взаємодію підсистем один з одним.

Нарешті, кожен пакет має свій простір імен, що дозволяє створювати однойменні класи в різних пакетах.

 

4 Оголошення пакету

Воно записується за допомогою ключового слова package, після якого вказується повна назва пакету. Наприклад, першим рядком (після коментарів) у файлі java / lang / Object.java йде:

 

package java.lang;

 

Це одночасно слугує оголошенням пакету lang, вкладеного в пакет java, і вказівкою, що оголошений нижче клас Object знаходиться в даному пакеті. Так складається повне ім'я класу java.lang.Object.

Якщо цей вислів відсутній, те такий модуль компіляції належить безіменному пакету. Цей пакет за замовчуванням обов'язково повинен підтримуватися реалізацією Java-платформи. Зверніть увагу, що він не може мати вкладених пакетів, так як складене ім'я пакету має обов'язково починатися з імені пакета верхнього рівня.

Пакет за замовчуванням був введений в Java для полегшення написання дуже невеликих або тимчасових програм, для експериментів. Якщо ж програма буде поширюватися для користувачів, то рекомендується розташувати її в пакеті, який, у свою чергу, повинен бути правильно названо.

 

5 Імпорт-вирази

Як буде розглянуто нижче, область видимості оголошення типу - пакет, у якому він розташовується. Це означає, що всередині даного пакету допускається звернення до типу за його простим ім'ям. З усіх інших пакетів необхідно звертатися за складеним іменем, тобто повне ім'я пакету плюс просте ім'я типу, розділені крапкою. Оскільки пакети можуть мати досить довгі імена, а тип може багаторазово використовуватися в модулі компіляції, таке обмеження може призвести до ускладнення вихідного коду й труднощам у розробці.

Для вирішення цієї проблеми вводяться import-вирази, які дозволяють імпортувати типи в модуль компіляції й далі звертатися до них за простими іменами. Існує два види таких виразів:

- імпорт одному типу;

- імпорт пакета.

Важливо підкреслити, що імпорт виразів є, по суті, підказкою для компілятора. Він користується ними, щоб для кожного простого імені типу з іншого пакета отримати його повне ім'я, яке й потрапляє в скомпільований код. Це означає, що таких виразів може бути дуже багато, включаючи й ті, що імпортують невживані пакети й типи, алі це ніяк не відіб'ється ні на розмірі, ні на якості бінарного коду. Також, байдуже, звертатися до типу за його повним ім'ям, або включити його в імпорт-вираз і звертатися по простому імені - результат буде один й той самий.

Вирази імпорту мають ефект тільки всередині модуля компіляції, у якому вони оголошені. Всі оголошення типів вищого рівня, що знаходяться в цьому ж модулі, можуть однаково користуватися імпортованими типами.

Вираз, що імпортує один тип, записується за допомогою ключового слова import і повного імені типу. Наприклад:

import java.net.URL;

 

Вираз, що імпортує пакет, включає в собі повне ім'я пакету наступним чином:

import java.awt .*;

 

Цей вираз робить доступними всі типи, що знаходяться в пакеті java.awt, за їх простому імені. Спроба імпортувати пакет, недоступний на момент компіляції, викличе помилку. Оскільки пакет java.lang містить типи, без яких неможливо створити жодну програму, він неявним чином імпортується в кожен модуль компіляції. Таким чином, всі типи з цього пакету доступні за їх простими іменами без будь-яких додаткових зусиль. Спроба імпортувати даний пакет ще раз буде проігнорована.

Допускається одночасно імпортувати пакет і який- небудь тип з нього:

6 Унікальність імен пакетів

Оскільки Java створювалась як мова, призначена для розповсюдження додатків через Internet, а додатки складаються зі структури пакетів, необхідно докласти деяких зусиль, щоб не стався конфлікт імен. Імена двох використовуваних пакетів можуть збігтися після значного часу після їх створення. Виправити такий стан звичайному програмісту буде вкрай важко.

Тому творці Java пропонують наступний спосіб унікального іменування пакетів. Якщо програма створюється розробником, у якого є Internet-сайт, або ж він працює на організацію, у якої є сайт, і доменне ім'я такого сайту, наприклад, company.com, то імена пакетів повинні починатися з цих же слів, виписаних у зворотному порядку : com.company. Подальші вкладені пакети можуть носити назви підрозділів компанії, пакетів, прізвища розробників, імена комп'ютерів і т.д.

Таким чином, пакет верхнього рівня завжди записується ASCII-літерами в нижньому регістрі й може мати одне з наступних імен:

- трьохбуквені com, edu, gov, mil, net, org, int (цей список розширюється);

- дволітерні, що позначають імена країн, такі як ru, su, de, uk та інші.

Якщо ім'я сайту суперечить вимогам до ідентифікаторів Java, то можна зробити наступні кроки:

- якщо в імені стоїть заборонений символ, наприклад, тире, те його можна замінити знаком підкреслення;

- якщо ім'я збігається з зарезервованим словом, можна в кінці додати знак підкреслення;

- якщо ім'я починається з цифри, можна на початку додати знак підкреслення.

Приклади назв пакетів, складених за такими правилами:

 

Однак, звичайно, ніхто не вимагає, щоб Java-пакети були обов'язково доступні на Internet-сайті, який дав їм ім'я. Швидше була зроблена спроба скористатися існуючою системою імен замість того, щоб створювати нову для іменування бібліотек.

 

7 Призначення модифікаторів доступу

Дуже часто права доступу розцінюються як якийсь елемент безпеки коду: мовляв, необхідно захищати класи від «неправильного» використання. Наприклад, якщо в класі Human (чоловік) є поле age (вік людини), то який-небудь програміст навмисно або через незнання може присвоїти цьому полю від'ємне значення, після чого об'єкт стані працювати неправильно, можуть з'явитися помилки. Для захисту такого поля age необхідно оголосити його private.

Це досить поширена крапка зору, проте треба визнати, що вона далека від істини. Основним змістом розмежування прав доступу є забезпечення невід'ємної властивості об'єктної моделі - інкапсуляції, тобто приховування реалізації.

Тобто, функціональність класу необхідно розділяти на відкритий інтерфейс, що описує дії, які будуть використовувати зовнішні типи, і на внутрішню реалізацію, яка застосовується тільки всередині самого класу. Зовнішній інтерфейс надалі модифікувати неможливо, або дуже складно, для великих систем, тому його потрібно продумувати особливо ретельно. Деталі внутрішньої реалізації можуть бути змінені на будь-якому етапі, якщо вони не змінюють логіку роботи всього класу. Завдяки такому підходу реалізується одна з базових характеристик об'єктної моделі - інкапсуляція, і забезпечується важлива переваги технології ООП - модульність.

Таким чином, модифікатори доступу вводяться не для захисту типу від зовнішнього користувача, а, навпаки, для захисту, або позбавлення, користувача від зайвих залежностей від деталей внутрішньої реалізації. Що ж стосується неправильного застосування класу, то його творцям потрібно прагнути до того, щоб клас був простий у застосуванні, тоді таких проблем не виникне, адже програміст не стане навмисно писати код, який породжує помилки в його програмі.

Звичайно, таке розбиття на зовнішній інтерфейс і внутрішню реалізацію не завжди очевидний, й, часто умовний. Для полегшення завдання технічних дизайнерів класів в Java уведено не два (public і private), а чотири рівня доступу.

Розмежування доступу в Java

Рівень доступу елемента мови є статичною властивістю, задається на рівні коду й завжди перевіряється під час компіляції. Спроба звернутися безпосередньо до закритого елементу викличе помилку.

В Java модифікатори доступу вказуються для:

- типів (класів та інтерфейсів) оголошення верхнього рівня;

- елементів вказівних типів (полів, методів, внутрішніх типів);

- конструкторів класів.

Як наслідок, масив також може бути недоступний у тому випадку, якщо недоступний тип, на основі якого він оголошений.

Всі чотири рівня доступу мають лише елементи типів і конструктори. Це:

- public;

- private;

- protected;

- якщо не вказано ні один з цих трьох типів, те рівень доступу визначається за замовчуванням (default).

Перші два з їх вже були розглянуті. Останній рівень (доступ за замовчуванням) згадувався в минулій лекції - він допускає звернення з того ж пакету, де оголошений і сам цей клас. З цієї заподій пакети в Java є не просто набором типів, а більш структурованою одиницею, так як типи всередині одному пакету можуть більше взаємодіяти один з одним, ніж з типами з інших пакетів.

Нарешті, protected дає доступ спадкоємцям класу. Зрозуміло, що спадкоємцям може знадобитися доступ до деяких елементів батька, з якими не доводити мати справу зовнішнім класам.

Однак описана структура не дозволяє впорядкувати модифікатори доступу так, щоб кожен наступний суворо розширював попередній. Модифікатор protected може бути зазначень для спадкоємця з іншого пакета, а доступ за замовчуванням допускає звернення з класів-ненаследніков, якщо смороду знаходяться в тому ж пакеті. З цієї заподій можливості protected були розширені таким чином, що він включає в собі доступ всередині пакету. Отже, модифікатори доступу упорядковуються наступним чином (від менш відкритих - до більш відкритим):

- private

- (None) default

- protected

- public

Тепер розглянемо, які модифікатори доступу можливі для різних елементів мови.

- пакети доступні завжди, тому в них немає модифікаторів доступу (можна сказати, що всі смороду public, тобто будь-який існуючий у системі пакет може використовуватися з будь-якої крапки програми).

- типи (класи та інтерфейси) верхнього рівня оголошення. При їх оголошенні існує всього дві можливості: вказати модифікатор public чи не вказувати його. Якщо доступ до типу є public, те це означає, що він доступний з будь-якої крапки коду. Якщо ж він не public, те рівень доступу призначається за замовчуванням: тип доступний тільки всередині того пакету, де він оголошений.

- масив має тої ж рівень доступу, що й тип, на основі якого він оголошений (природно, всі примітивні типи є повністю доступними).

- елементи й конструктори об'єктних типів. Мають усі чотири можливі значення рівня доступу. Всі елементи інтерфейсів є public.

Для типів оголошення верхнього рівня немає необхідності у всіх чотирьох рівнях доступу. Private-типи утворювали б закриту міні-програму, ніхто не міг би їх використовувати. Типи, доступні тільки для спадкоємців, також не були визнані корисними.

Розмежування доступу позначаються не тільки на зверненні до елементів об'єктних типів або пакетів (через складене ім'я або пряме звернення), алі також при виклику конструкторів, спадкуванні, приведенні типів. Імпортувати недоступні типи забороняється. Перевірка рівня доступу проводитися компілятором.

Розглянемо базові можливості оголошення класів. Оголошення класу складається йз заголовка й тіла класу.

Спочатку вказуються модифікатори доступу класу. Допустимими є public, або його відсутність – доступ за замовчуванням.

Клас може бути оголошений як final. У цьому випадку не допускається створення спадкоємців такого класу. На своїй гілці спадкування він є останнім. Клас String і класи-обгортки, наприклад, являють собою final-класи.

Після списку модифікаторів вказується ключове слово class, а потім ім'я класу - коректний Java-ідентифікатор. Таким чином, найкоротшим оголошенням класу може бути такий модуль компіляції:

 

class A {}

 

Фігурні дужки позначають тіло класу.

Зазначений ідентифікатор стає простим ім'ям класу. Далі заголовок може містити ключове слово extends, після якого має бути вказано ім'я (просте чи складене) доступного не final класу. У цьому випадку оголошений клас успадковується від зазначеного класу. Якщо вираз extends не застосовується, то клас успадковується безпосередньо від Object. Вираз extends Object допускається але ігнорується.

 

8 Тіло класу

Тіло класу може містити оголошення елементів (members) класу:

- полів;

- внутрішніх типів (класів та інтерфейсів);

І інших допустимих конструкцій:

- конструкторів;

- ініціалізаторов

- статичних ініціалізаторов.

Елементи класу мають імена й передаються в спадок, не-елементи - ні. Для елементів прості імена вказуються при оголошенні, складові формуються з імені класу, або імені змінної об'єктного типу, і простого імені елемента. Областю видимості елементів є всі оголошення тіла класу. Допускається застосування будь-якого з усіх чотирьох модифікаторів доступу. Нагадуємо, що догоди іменування класів та їх елементів обговорювалися в минулій лекції.

Не елементи не володіють іменами, а тому не можуть бути викликані явно. Їх викликає сама віртуальна машина. Наприклад, конструктор викликається при створенні об'єкту. З тієї ж заподій не-елементи не володіють модифікаторами доступу.

Елементами класу є елементи, описані в оголошенні тіла класу й передані в спадок від класу-батька (крім Object - єдиного класу, який не має одного з батьків) і всіх реалізованих інтерфейсів за умови достатнього рівня доступу. Таким чином, якщо клас містить елементи з доступом за замовчуванням, те його спадкоємці з різних пакетів будуть володіти різним набором елементів. Класи з того ж пакету можуть користуватися повним набором елементів, а з інших пакетів - тільки protected і public. private-елементи в спадок не передаються.

Поля й методи можуть мати однакові імена, оскільки звернення до полів завжди записується без дужок, а до методів - завжди з дужками.

Оголошення конструкторів

Формат оголошення конструкторів схожий на спрощений формат оголошення методів. Також виділяють заголовок і тіло конструктора. Заголовок складається, по-перше, з модифікаторів доступу (ніякі інші модифікатори окрім public неприпустимі). По-друге, вказується ім'я класу, яке можна розцінювати подвійно. Можна вважати, що ім'я конструктора збігається з ім'ям класу. А можна розглядати конструктор як безіменний, а ім'я класу - як тип значення, адже конструктор може породити тільки об'єкт класу, у якому він оголошений. Це виключно право смаку, тому що на форматі оголошення ніяк не позначається.

Тіло конструктора порожнім бути не може й тому завжди описується у фігурних дужках (для найпростіших реалізацій дужки можуть бути порожніми).

Однак логіка роботи конструкторів має й деякі важливі особливості. Оскільки при їх виклику здійснюється створення й ініціалізація об'єкта, стає зрозуміло, що такий процес не може відбуватися без звернення до конструкторів всіх батьківських класів. Тому вводиться обов'язкове правило - першим рядком у конструкторі має бути звернення до батьківського класу, яке записується за допомогою ключового слова super.

Вираз super може стояти тільки на першому рядку конструктора. Часто можна побачити конструктори взагалі без такого виразу. У цьому випадку компілятор першим рядком за замовчуванням додає виклик батьківського конструктора без параметрів (super()). Якщо в батьківського класу такого конструктора немає, вираз super обов'язково має бути записано явно (і саме на першому рядку), оскільки необхідна передача вхідних параметрів.

Клас обов'язково пвинен мати конструктор, інакше неможливо породжувати об'єкти ні від нього, ні від його спадкоємців. Тому якщо в класі не оголошено ні одного конструктора, компілятор додає один за замовчуванням. Це public-конструктор без параметрів і з тілом, описаним парою порожніх фігурних дужок. З цього випливає, що таке можливо тільки для класів, у батьків яких оголошено конструктор без параметрів, інакше виникне помилка компіляції. Зверніть увагу, що якщо потім у такий клас додається конструктор (не важливо, з параметрами або без), то конструктор за замовчуванням більше не вставляється.



<== попередня лекція | наступна лекція ==>
Ключове слово abstract | Тема 10 Робота з інтерфейсами


Онлайн система числення Калькулятор онлайн звичайний Науковий калькулятор онлайн