Заданием модификатора доступа члена класс может контролировать, какая информация доступна для клиентов (т.е. других классов). Модификаторы помогают классу определить контракт, для того чтобы клиенты точно знали о сервисах, которые он предоставляет. Уровень доступа может быть одним из следующих:
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
.
// Имя Файла: 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.
protected
) членыЗащищенные (protected
) члены доступны во всех классах в пакете, содержащем их класс, и во всех подклассах их класса в любом пакете, откуда виден класс. Другими словами, не подклассы из других пакетов не могут обратиться к защищенным членам классов из других пакетов. Это ограничение доступа менее строго, чем доступ по умолчанию.
Если поле superclassVarA
и метод superclassMethodA
в примере 4.9 имеют модификатор доступа protected
, то они доступны внутри пакета packageA
, а в других пакетах только в подклассах.
public class SuperclassA {
protected int superclassVarA; // (2)
protected void superclassMethodA() {/*...*/} // (3)
}
Клиент 4 в пакете packageB
не имеет доступа к этим членам, как показано на рис.4.5
Подкласс из другого пакета может получить доступ к защищенным членам родительского класса только через ссылку его собственного типа или его подтипов. Ниже приведено определение класса 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.
private
) членыЭто наиболее жесткий из всех модификаторов доступа. Private
-члены (закрытые члены) недоступны из других классов. Это правило применимо и к подклассам независимо от того, в том же самом они пакете или нет. Поскольку к ним нельзя обратиться по простому имени из подкласса, они также и не могут быть унаследованы подклассом. Это не следует путать с существованием такого члена в состоянии объекта подкласса. Обычная стратегия проектирования заключается в том, чтобы сделать все поля закрытыми (private
) и обеспечить доступ к ним через общедоступные (public
) методы. Вспомогательные методы часто объявляют как private
, так как они не представляют важности для клиентов.
В примере 4.9, если поле superclassVarA
и метод superclassMethodA
будут иметь модификатор доступа private
, то к ним не смогут обратиться никакие другие клиенты.
public class SuperclassA {
private int superclassVarA; // (2)
private void superclassMethodA() {/*...*/} // (3)
}
Ни один из клиентов на рис. 4.7 не может обратиться к этим членам.
Таким образом, модификаторы доступа для членов класса:
public
— доступен отовсюду;
protected
— доступен для всех классов в своем же пакете и доступен из других пакетов только для подклассов своего класса.
default
— доступен только для классов в том же пакете, что и их класс, включая подклассы;
private
— доступен только в своем собственном классе и больше нигде.
Другие модификаторы для классов | Другие модификаторы для членов |