Материал предоставлен https://it.rfei.ru

Модификаторы доступа членов класса

Заданием модификатора доступа члена класс может контролировать, какая информация доступна для клиентов (т.е. других классов). Модификаторы помогают классу определить контракт, для того чтобы клиенты точно знали о сервисах, которые он предоставляет. Уровень доступа может быть одним из следующих:

  • public (общедоступный);
  • protected (защищенный);
  • default (также называемый пакетным доступом);
  • private (закрытый).

Член класса имеет пакетный доступ или доступ по умолчанию, когда для него не задан ни один модификатор.

Во время следующего рассмотрения модификаторов доступа членов класса имейте в виду, что модификатор доступа члена имеет значение, только если класс (или один из его подклассов) доступен для клиента. Также обратите внимание, что для члена может быть задан только один модификатор доступа.

В нотации UML префиксы + , # и -, когда они применяются к имени члена, указывают соответственно на доступ public, protected и private. Отсутствие префикса указывает на уровень доступа по умолчанию или пакетный.

Общедоступные (public) члены

Уровень доступа public (общедоступный) накладывает наименьшие ограничения из всех доступных модификаторов. Public-член доступен отовсюду, и из содержащего его пакета, и из других пакетов, откуда виден данный класс. Это справедливо и для членов экземпляра и статических членов.

В примере 4.9 приведены два файла исходного кода, что показано в строках (1) и (6). Иерархия пакетов, определяемая файлами исходного кода, изображена на рис. 4.4, который показывает два пакета packageA и packageB, содержащие соответствующие классы. Классы в пакете packageB используют классы из пакета packageA. SuperclassA в пакете packageA имеет два подкласса: SubclassA в пакете packageA и SubclassB в пакете packageB.

Пример 4.9. Уровень доступа членов public

// Имя Файла: SuperclassA.java                           (1)
package packageA;

public class SuperclassA {
    public int superclassVarA;                       // (2)
    public void superclassMethodA() {/*...*/}        // (3)
}

class SubclassA extends SuperclassA {
    void subclassMethodA() { superclassVarA = 10; }  // (4) OK.
}

class AnyClassA {
    SuperclassA obj = new SuperclassA();
    void anyClassMethodA() {
        obj.superclassMethodA();                     // (5) OK.
    }
}
// Имя Файла: SubclassB.java                             (6)
package packageB;
import packageA.*;

public class SubclassB extends SuperclassA {
    void subclassMethodB() { superclassMethodA(); }  // (7) OK.
}

class AnyClassB {
    SuperclassA obj = new SuperclassA();
    void anyClassMethodB() {
        obj.superclassVarA = 20;                     // (8) OK.
    }
}

В примере 4.9 проиллюстрирован доступ путем задания модификаторов доступа для поля superclassVarA и метода superclassMethodA в строках (2) и (3) соответственно, определенных в классе SuperclassA. К этим членам в примере 4.9 идет обращение из четырех разных клиентов.

  • Клиент 1. Из подкласса в том же пакете, который обращается к унаследованному полю. Таким клиентом является SubclassA в строке (4).
  • Клиент 2. Из классов в том же пакете, который не является подклассом нашего класса и вызывает метод на экземпляре класса. Таким клиентом является AnyClassA в строке (5).
  • Клиент 3. Из подкласса в другом пакете, который вызывает унаследованный метод. Таким клиентом является SubclassB в строке (7).
  • Клиент 4. Из класса в другом пакете, который не является подклассом нашего класса, а обращается к полю экземпляра класса. Таким клиентом является AnyClassB в строке (8).

В примере 4.9 поле superclassVarA и метод superclassMethodA() имеют доступ public, поэтому они доступны всем вышеперечисленным клиентам. Подклассы могут обращаться к унаследованным общедоступным (public) членам по их простому имени, и все клиенты могут обращаться к publiс-членам через экземпляр класса. Доступ public изображен на рис. 4.4.

Рис. 4.4. Доступ public

Защищенные (protected) члены

Защищенные (protected) члены доступны во всех классах в пакете, содержащем их класс, и во всех подклассах их класса в любом пакете, откуда виден класс. Другими словами, не подклассы из других пакетов не могут обратиться к защищенным членам классов из других пакетов. Это ограничение доступа менее строго, чем доступ по умолчанию.

Если поле superclassVarA и метод superclassMethodA в примере 4.9 имеют модификатор доступа protected, то они доступны внутри пакета packageA, а в других пакетах только в подклассах.

public class SuperclassA {
    protected int superclassVarA;                    // (2)
    protected void superclassMethodA() {/*...*/}     // (3)
}

Клиент 4 в пакете packageB не имеет доступа к этим членам, как показано на рис.4.5

Рис. 4.5. Уровень доступа protected

Подкласс из другого пакета может получить доступ к защищенным членам родительского класса только через ссылку его собственного типа или его подтипов. Ниже приведено определение класса SubclassB в пакете packageB из примера 4.9, иллюстрирующее этот момент.

// Имя файла: SubclassB.java
package packageB;
import packageA.*;

public class SubclassB extends SuperclassA {         // В packageB.

    SubclassB objRefB = new SubclassB();             // (1)

    void subclassMethodB(SuperclassA objRefA) {
        objRefB.superclassMethodA();                 // (2) OK.
        objRefB.superclassVarA = 5;                  // (3) OK.
        // objRefA.superclassMethodA();              // (4) Не OK.
        // objRefA.superclassVarA = 10;              // (5) Не OK.
    }
}

В классе SubclassB определено поле типа SubclassB (objRefB). Метод subclassMethodB() имеет формальный параметр objRefA типа SuperclassA. Доступ разрешен к защищенному члену класса SuperclassA в пакете packageA по ссылке типа подкласса, как показано в строках (2) и (3), но не по ссылке с типом его родителя, как показано в строках (4) и (5). Обращение к полю superclassVarA и вызов метода superclassMethodA() происходит в классе SubclassB. Эти члены объявлены в классе SuperclassA. Класс SubclassB не включен в реализацию класса SuperclassA, который является типом ссылки objRefA. Следовательно, доступ к защищенным членам в строках (4) и (5) не разрешается, так как они не являются членами объекта, который может быть с гарантией реализован обращающимся к ним кодом.

Доступ к защищенным членам суперкласса может быть разрешен через любые ссылки типа SubclassB. Вышеприведенное ограничение помогает гарантировать, что если подкласс будет находиться в пакетах, отличных от пакета родителя, то он сможет обратиться только к защищенным членам своего суперкласса в своей части иерархии наследования реализации.

Доступ по умолчанию для членов

Когда для члена не определен ни один модификатор доступа, он доступен только для других классов в пакете его же класса. Даже если его класс видим в другом (возможно вложенном) пакете, к члену все равно доступа нет. Доступ по умолчанию накладывает более серьезное ограничение в сравнении с доступом protected.

В примере 4.9 если поле superclassVarA и метод superclassMethodA задать без модификаторов доступа, то они будут доступны только внутри пакета packageA и не из каких других (даже вложенных) пакетов.

public class SuperclassA {
    int superclassVarA;                             // (2)
    void superclassMethodA() {/*...*/}              // (3)
}

Клиенты из пакета packageB (т.е. клиенты 3 и 4) не могут обратиться к этим членам. Такая ситуация изображена на рис.4.6.

Рис.4.6. Доступ по умолчанию

Закрытые (private) члены

Это наиболее жесткий из всех модификаторов доступа. Private-члены (закрытые члены) недоступны из других классов. Это правило применимо и к подклассам независимо от того, в том же самом они пакете или нет. Поскольку к ним нельзя обратиться по простому имени из подкласса, они также и не могут быть унаследованы подклассом. Это не следует путать с существованием такого члена в состоянии объекта подкласса. Обычная стратегия проектирования заключается в том, чтобы сделать все поля закрытыми (private) и обеспечить доступ к ним через общедоступные (public) методы. Вспомогательные методы часто объявляют как private, так как они не представляют важности для клиентов.

В примере 4.9, если поле superclassVarA и метод superclassMethodA будут иметь модификатор доступа private, то к ним не смогут обратиться никакие другие клиенты.

public class SuperclassA {
    private int superclassVarA;                      // (2)
    private void superclassMethodA() {/*...*/}       // (3)
}

Ни один из клиентов на рис. 4.7 не может обратиться к этим членам.

Рис. 4.7. Доступ private

Таким образом, модификаторы доступа для членов класса:

  • public — доступен отовсюду;
  • protected — доступен для всех классов в своем же пакете и доступен из других пакетов только для подклассов своего класса.
  • default — доступен только для классов в том же пакете, что и их класс, включая подклассы;
  • private — доступен только в своем собственном классе и больше нигде.
Другие модификаторы для классовДругие модификаторы для членов