Заданием модификатора доступа члена класс может контролировать, какая информация доступна для клиентов (т.е. других классов). Модификаторы помогают классу определить контракт, для того чтобы клиенты точно знали о сервисах, которые он предоставляет. Уровень доступа может быть одним из следующих:
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 идет обращение из четырех разных клиентов.
SubclassA в строке (4).
AnyClassA в строке (5).
SubclassB в строке (7).
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 — доступен только в своем собственном классе и больше нигде.
| Другие модификаторы для классов | Другие модификаторы для членов |