Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
31
Добавлен:
14.04.2015
Размер:
592.9 Кб
Скачать

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

Рівень доступу елемента мови є статичним властивістю, задається на рівні

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

викличе помилку.

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

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

• елементів посилальних типів (полів, методів, внутрішніх типів);

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

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

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

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

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

• public;

• private;

• protected;

• якщо не вказано ні один з цих 3 типів, то рівень доступу визначається за замовчуванням

(Default).

Перші два з них вже були розглянуті. Останній рівень (доступ за замовчуванням)

згадувався в минулому розділі - він дозволяє звернення з того ж пакета, де оголошено

і сам цей клас. З цієї причини пакети в Java є не просто набором типів, а

більш структурованою одиницею, так як типи всередині одного пакета можуть більше

взаємодіяти один з одним, ніж з типами з інших пакетів.

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

знадобитися доступ до деяких елементів батька, з якими не потрібно мати

справа зовнішнім класам.

Однак описана структура не дозволяє впорядкувати модифікатори доступу так, щоб

кожен наступний строго розширював попередній. Модифікатор protected може бути

вказаний для спадкоємця з іншого пакета, а доступ за умовчанням дозволяє звернення

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

можливості protected були розширені таким чином, що він включає в себе доступ

усередині пакета. Отже, модифікатори доступу упорядковуються так (від

менш відкритих - до більше):

private

(None) default

protected

public

Ця послідовність буде використана далі при вивченні деталей спадкування

класів.

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

мови.

• Пакети завжди доступні, тому у них немає модифікаторів доступу (можна сказати,

що всі вони public, тобто, будь-який існуючий в системі пакет може бути

використаний з будь-якої точки програми).

• Типи (класи та інтерфейси) верхнього рівня оголошення. При їх оголошенні є

всього дві можливості: вказати модифікатор public або не вказувати його. Якщо доступ

до типу є public, то це означає, що він доступний з будь-якої точки коду. Якщо ж

він не public, то рівень доступу призначається за умовчанням: тип доступний тільки всередині

того пакету, де він оголошений.

• Масив має той же рівень доступу, що і тип, на основі якого він оголошений

(Природно, все примітивні типи є повністю доступними).

• Елементи й конструктори об'єктних типів. Мають усіма 4 можливими значеннями

рівня доступу. Всі елементи інтерфейсів є public.

Для типів оголошення верхнього рівня немає необхідності у всіх 4 рівнях доступу.

private-типи утворювали б закриту міні-програму, ніхто не міг би їх використовувати.

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

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

типів або пакетів (через складене ім'я або пряме звернення), але також при виклику

конструкторів, успадкування, приведення типів. Забороняється імпортувати недоступні

типи.

Перевірка рівня доступу проводиться компілятором. Зверніть увагу на наступні

приклади:

public class Wheel {

private double radius;

public double getRadius () {

return radius;

}

}

Значення поля radius не доступно зовні класу, однак відкритий метод getRadius ()

коректно повертає його.

Розглянемо наступні два модулі компіляції:

package first;

/ / Певний клас Parent

public class Parent {

}

package first;

/ / Клас Child успадковується від класу Parent,

/ / Але має обмеження доступу за умовчанням

class Child extends Parent {

}

public class Provider {

public Parent getValue () {

return new Child ();

}

}

До методу getValue () класу Provider можна звернутися і з іншого пакета, не тільки з

пакета first, оскільки метод оголошений як public. Як видно, цей метод повертає

екземпляр класу Child, який не доступний з інших пакетів. Проте наступний виклик

є коректним:

package second;

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

import first. *;

public class Test {

public static void main (String s []) {

Provider pr = new Provider ();

Parent p = pr.getValue ();

System.out.println (p.getClass (). GetName ());

/ / (Child) p - призведе до помилки компіляції!

}

}

Результатом буде:

first.Child

Тобто, насправді в класі Test робота йде з примірником недоступного класу

Child, що можливо, оскільки звернення до нього робиться через відкритий клас Parent.

Спроба ж зробити явне приведення викличе помилку. Так, тип об'єкта "Вгадай" вірно,

але доступ до закритого типу завжди заборонений.

Наступний приклад:

public class Point {

private int x, y;

public boolean equals (Object o) {

if (o instanceof Point) {

Point p = (Point) o;

return px == x && py == y;

}

return false;

}

}

У цьому прикладі оголошується клас Point з двома полями, що описують координати

точки. Зверніть увагу, що поля повністю закриті - private. Далі спробуємо

перевизначити стандартний метод equals () таким чином, щоб для аргументів,

є екземплярами класу Point, або його спадкоємців (логіка роботи оператора

intsanceof) поверталося справжнє значення в разі рівності координат. Зверніть

увагу на рядок, де робиться порівняння координат - для цього доводиться звертатися

до private-полям іншого об'єкта!

Тим не менш, така дія абсолютно коректно, оскільки private допускає

звернення з будь-якої точки класу, незалежно від того, до якого саме об'єкту воно

виробляється.

Інші приклади розмежування доступу в Java будуть розглядатися по ходу курсу.

3. Оголошення класів

Розглянемо базові можливості оголошення класів.

Оголошення класу складається з заголовка і тіла класу.

3.1. Тема класу

Спочатку вказуються модифікатори класу. Модифікатори доступу для класу вже

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

Клас може бути оголошений як final. В цьому випадку не допускається створення спадкоємців

такого класу. На своїй гілці успадкування він є останнім. Клас String і класи-

обгортки, наприклад, є final-класами.

Після списку модифікаторів вказується ключове слово class, а потім ім'я класу -

коректний Java-ідентифікатор. Таким чином, найкоротшим оголошенням класу може

бути такий модуль компіляції:

class A {}

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

Зазначений ідентифікатор стає простим ім'ям класу. Повне складене ім'я

класу будується з повного складного імені пакета, в якому він оголошений (якщо це не

безымянный пакет), и простого имени класса, разделенных точкой. Область видимости

класса, где он может быть доступен по своему простому имени - его пакет.

Далее заголовок может содержать ключевое слово extends, после которого должно быть

указано имя (простое или составное) доступного не-final класса. В этом случае объявляемый

класс наследуется от указанного класса. Если выражение extends не применяется, то класс

наследуется напрямую от Object. Выражение extends Object допускается и игнорируется.

class Parent {} // = class Parent extends Object {}

final class LastChild extends Parent {}

// class WrongChild extends LastChild {} // ошибка!!

Попытка расширить final-класс приведет к ошибке компиляции.

Если в объявлении класса A указано выражение extends B, то класс A называют прямым

наследником класса B.

Класс A считается наследником класса B если:

• A является прямым наследником B;

• либо существует класс C, который является наследником B, а A является наследником

C (это правило применяется рекурсивно).

Таким образом можно проследовать цепочки наследования на несколько уровней вверх.

Если компилятор обнаруживает, что класс является своим наследником, то возникает

ошибка компиляции:

Заголовок класса

// пример вызовет ошибку компиляции

class A extends B {}

class B extends C {}

class C extends A {} // ошибка! Класс А стал своим наследником

Далее в заголовке может быть указано ключевое слово implements, за которым должно

следовать перечисление через запятую имен (простых или составных, повторения

запрещены) доступных интерфейсов:

public final class String implements Serializable, Comparable {}

В этом случае говорят, что класс реализует перечисленные интерфейсы. Як видно з

примера, класс может реализовывать любое количество интерфейсов. Если выражение

Соседние файлы в папке Програмне_забезпечення_ОС_ИНФ_5_сем