Модификаторы доступа
Вы уже, наверное, неоднократно видели в примерах использование таких ключевых слов, как public , private и protected . Это модификаторы доступа в языке Java. Сегодня мы рассмотрим для чего они используются.
Очень часто в Java доступ к некоторым членам класса желательно ограничить. Для этого и нужны модификаторы доступа, которые могут присутствовать в объявлении члена класса. Модификатор доступа указывается перед остальной спецификации типа члена, например:
public int i; private static double j; private int myMethod (int а , char b ) < / / . . .
Существует три модификатора доступа: public , private и protected и четыре уровня доступа:
- public (открытый) - когда член объявляется с модификатором доступа public , он становится доступным из любого другого кода.
- private (закрытый) - когда член класса объявляется с модификатором доступа private , он доступен только другим членам этого же класса.
- protected (защищенный) - применяется только при наследовании.
- Уровень доступа, предоставляемый по умолчанию - в отсутствие модификатора доступа по умолчанию член класса считается открытым в своем пакете, но недоступным для кода, находящегося за пределами этого пакета.
Ограничение уровня доступа к членам класса - это еще один механизм реализации принципа инкапсуляции.
2. Отличие уровня доступа по умолчанию, public и private
Рассмотрим отличие уровня доступа по умолчанию, public и private на следующем примере. В классе Modificators объявлено три переменные с разным уровнем доступа. Внутри самого класса Modificators можно обратится к любой из этих переменных, как показано в методе toString() :
package oop; public class Modificators < public int publicVar; // открытый уровень доступа private int privateVar; // закрытый уровень доступа int defaultVar; // уровень доступа по умолчанию public String toString() < return "Modificatorspackage oop; public class ModificatorsDemo1 < public static void main(String[] args) < Modificators object = new Modificators(); object.defaultVar = 10; object.publicVar = 20; //object.privateVar = 100; // Ошибка компиляции! >>
Создадим класс похожий на ModificatorsDemo1 , но в другом пакете. В этом классе мы точно также не можем обратиться к private переменной, но теперь и переменная с уровнем доступа по умолчанию тоже недоступна:
package oop.p2; import oop.Modificators; public class ModificatorsDemo2 < public static void main(String[] args) < Modificators object = new Modificators(); //object.defaultVar = 10;// Ошибка компиляции! object.publicVar = 20; //object.privateVar = 100; // Ошибка компиляции! >>
3. Уровень доступа protected в Java
Уровень доступа protected используется при наследовании. Он очень похож на уровень доступа по умолчанию, который раскрывает область видимости только для классов определенных в том же пакете. Protected модификатор раскрывает область видимости для классов определенных в том же пакете или для классов наследников.
Рассмотрим разницу между уровнями доступа на следующем примере.
Объявим в классе Parent три метода с разными уровнями доступа:
package oop.p1; public class Parent < public void publicAccessMethod() < >void defaultAccessMethod() < >protected void protectedAccessMethod() < >>
Определяем класс наследник в другом пакете:
package oop.p2; import oop.p1.Parent; public class Child extends Parent < public void someMethod() < publicAccessMethod(); //defaultAccessMethod(); protectedAccessMethod(); >>
Из класса Child нет доступа к default членам класса Parent , но есть доступ к protected и public членам класса Parent .
Рассмотрим следующий класс - AccessClass , находящийся в пакете отличном от класса Parent . Он не является наследником Parent , поэтому доступ из него разрешен только к public методам:
package oop.p2; import oop.p1.Parent; public class AccessClass < public static void main(String[] args) < Parent parent = new Parent(); parent.publicAccessMethod(); // parent.defaultAccessMethod(); // parent.protectedAccessMethod(); >>
Перенесем класс AccessClass в пакет, в котором находится класс Parent , и мы получим доступ не только к public членам класса, но и к protected и default :
package oop.p1; public class AccessClass < public static void main(String[] args) < Parent parent = new Parent(); parent.publicAccessMethod(); parent.defaultAccessMethod(); parent.protectedAccessMethod(); >>
4. Уровни доступа для класса
Для класса, не являющегося вложенным, может быть указан только один из двух возможных уровней доступа:
- По умолчанию - если у класса имеется уровень доступа по умолчанию, такой класс оказывается доступным только для кода из данного пакета.
- Открытый ( public ) - если класс объявлен как public , он доступен из любого другого кода.
Когда мы говорим, что код из одного класса ( class A ) имеет доступ к коду из другого класса ( class B ), это означает что класс A может делать одну из трех вещей:
- создать экземпляр класса B ,
- наследовать класс B ,
- иметь доступ к определенным членам класса B .
В этом примере показана попытка наследовать класс HotBevarage с уровнем доступа по умолчанию из другого пакета. В этом случае возникнет ошибка компиляции:
package oop.p1; class HotBeverage<>
package oop.p2; //import oop.p1.HotBeverage; public class Tea //extends HotBeverage<>
Если класс оказывается открытым, он должен быть единственным открытым классом, объявленным в файле, а имя этого файла должно совпадать с именем класса. Например:
public class Beverage <> class HotBeverage<>
- Процедурное и объектно-ориентированное программирование
- Принципы ООП
- Классы и объекты
- Конструктор
- Ключевое слово this
- Перегрузка
- Стек и куча
- Передача объектов в методы
- Java varargs
- Рекурсия
- Сборщик мусора и метод finalize
- Наследование
- Ключевое слово super
- Геттеры и сеттеры
- Переопределение методов
- Абстрактные классы и методы
- Ключевое слово final
- Задания
Модификаторы private, protected, public в Java
Модификаторы доступа private, protected, public ставятся перед именем класса, метода или поля и ограничивают доступ к нему. К локальным переменным модификаторы доступа не применимы.
Помимо этих трех явных модификаторов, есть еще так называемый default-модификатор, или модификатор по умолчанию, иначе говоря — это отсутствие всякого модификатора. Но это отсутствие тоже подразумевает свои правила доступа (видимость только внутри пакета).
Зачем нужны модификаторы доступа
Модификаторы доступа существуют для того, чтобы сделать код надежнее и защищеннее. Нужно максимально ограничивать видимость своих классов, методов и полей, и открывать их только там, где это действительно необходимо. Если вы откроете что-то лишнее, то другой разработчик (или даже вы сами) может по ошибке воспользоваться открытым классом/методом. Чем это чревато? А тем, что если в дальнейшем вы исправите свой код (отвечающий за внутреннюю реализацию, но открытый для пользования извне), то код другого программиста перестанет работать, так как опирается на ваш код. Открывать нужно только то, что вы планируете поддерживать и что будет стабильно работать (без изменения контракта) во всех последующих версиях. Все остальное — внутренняя реализация, которая касается только вас и может меняться, ее никто не должен использовать.
Нормально сделать видимым, например, один класс вашего пакета и только методы, предназначенные для внешнего использования (методы API). Все остальное скрыть. Это называется инкапсуляцией (скрытием реализации).
Правила доступа
На картинке показаны правила доступа к полю или методу с конкретным модификатором (последний столбец — про модули, они появились в Java 9):
Модификатор private
Это самый ограничивающий модификатор. К полям и методам, помеченным ключевым словом private, можно обратиться только из того же класса, где они находятся.
Допустим у нас есть класс A с private полем privateVar и с private методом privateMethod(). Из класса A мы можем обращаться к полю, см. обращение this.privateVar:
package accessmodifiers.priv; public class A < private int privateVar = 1; private void privateMethod() < System.out.println("A private method is printing " + this.privateVar); >public static void main(String[] args) < A a = new A(); a.privateVar = 2; a.privateMethod(); >>
А теперь попробуем обратиться к этому полю и методу из класса B, код не скомпилируется:
package accessmodifiers.priv; public class B < void testAccess() < A a = new A(); a.privateVar = 10; // illegal a.privateMethod(); // illegal >>
Вышеприведенный код выдает ошибки компиляции:
The field A.privateVar is not visible The method privateMethod() from the type A is not visible
Иногда возникает вопрос
Можно ли в классе A получить доступ к private методам и полям другого объекта A (не текущего this)?
Да, можно. Обратите внимание на функцию main() из класса A, в которой создается новый объект A и идет обращение к его методам и полям (не через this):
package accessmodifiers.priv; public class A < private int privateVar = 1; private void privateMethod() < System.out.println("A private method is printing " + this.privateVar); >public static void main(String[] args) < A a = new A(); a.privateVar = 2; a.privateMethod(); >>
Как показано выше, мы обращаемся в методе main() к private полю privateVar другого объекта A, и это законно.
В Java ограничения доступа применимы на уровне класса, а не на уровне объекта (не обязательно, чтоб обращение шло к тому же экземпляру, главное, что он в том же классе). В Scala, например, существуют модификаторы доступа на уровне объекта
Можно ли переопределить private метод?
Нельзя, метод в подклассе не будет иметь никакого отношения к методу в суперклассе, так как private метод нигде не виден. Давайте попытаемся унаследоваться от класса A и «переопределить» private метод privateMethod():
public class SubA extends A < private void privateMethod() < System.out.println("B private method is printing "); >>
Попробуем создать объект SubA и вызвать privateMethod() на A:
A a=new SubA(); a.privateMethod();
Как видите, срабатывает метод privateMethod() класса A, то есть переопределения не происходит:
A private method is printing 2
Это происходит потому, что метод privateMethod() класса SubA не переопределяет метод privateMethod() класса A, а является независимым методом.
Модификатор default
Если мы не ставим никакого модификатора доступа перед методом, полем или классом, то этот метод/поле/класс видимы из кода только внутри пакета, в котором они находятся.
Давайте продемонстрируем это. Создадим снова класс A в пакете .def:
package ru.sysout.accessmodifiers.def; public class A < int defaultVar = 1; void defaultMethod() < System.out.println("A default method is printing " + this.defaultVar ); >>
И создадим в этом же пакете класс B, из которого будем пытаться получить доступ к полям и методам A, как и раньше:
package ru.sysout.accessmodifiers.def; public class B < void testAccess() < A a = new A(); a.defaultVar = 10; // legal a.defaultMethod(); // legal >>
В этот раз код компилируется, все в порядке — доступ есть.
Если бы класс B находится в другом пакете (отличном от ru.sysout.accessmodifiers.def, в том числе в подпакете), то доступа бы не было.
Модификатор protected
Следующий по строгости — модификатор protected. Он также разрешает доступ к помеченным с помощью него полям и методам из кода внутри того же пакета. Но помимо этого, он дает поблажки подклассам, находящимся в другом пакете. Подкласс может обращаться к protected полям и методам суперкласса, даже если подкласс находится в другом пакете.
Снова создадим класс A с protected полем и методом:
package ru.sysout.accessmodifiers.prot; public class A < protected int protectedVar = 1; protected void protectedMethod() < System.out.println("A protected method is printing " + this.protectedVar); >>
Создадим в другом пакете класс C — наследника класса A и попытаемся получить доступ к полям методам класса A из класса C:
package ru.sysout.accessmodifiers.prot.sub; import ru.sysout.accessmodifiers.prot.A; public class C extends A < void testAccess(A a, C c) < this.protectedVar = 1;// legal this.protectedMethod();// legal // a.protectedVar = 10; // illegal c.protectedVar = 10; // legal // a.protectedMethod(); // illegal c.protectedMethod(); // legal >>
Как показано выше, обращение к полю и методу через this работает из другого пакета.
Также работает обращение ко всем другим экземплярам типа C, но к другим экземплярам типа A обращение не работает.
Модификатор public
Тут все просто — к полю и методу с модификатором public имеет доступ любой код. Давайте еще раз перепишем класс A:
package ru.sysout.accessmodifiers.pub; public class A < public int publicVar = 1; public void publicMethod() < System.out.println("A public method is printing " + this.publicVar); >>
И обратимся к его полю и методу из класса B, который находится в другом пакете и никакого отношения к классу A не имеет:
package ru.sysout.accessmodifiers.pub.sub; import ru.sysout.accessmodifiers.pub.A; public class B < void testAccess() < A a = new A(); a.publicVar = 10; // legal a.publicMethod(); // legal >>
Все получилось, обращение работает.
Какой модификатор выбрать?
Правило выбора модификатора такое — надо по возможности выбирать:
То есть надо максимально ограничивать видимость члена класса. Сначала надо попробовать сделать все private, и при необходимости открывать видимость.
Итог
Мы рассмотрели тонкости использования модификаторов доступа. Код примеров можно посмотреть на GitHub.
Автор sysout Опубликовано 26.09.2018 16.11.2022 Рубрики Core Java
Модификаторы private, protected, public в Java: 2 комментария
В разделе «Может ли объект A получить доступ к private методам и полям другого объекта A?» код не соответствует смыслу написанного — пожалуйста исправьте его
Различие между модификаторами доступа public, protected, package-private и private в Java
Часто, при работе с классами и интерфейсами в Java, перед разработчиками встает вопрос выбора подходящего модификатора доступа. Иногда сложно понять, в каких случаях лучше использовать public , protected , private или package-private (по умолчанию).
Для примера, представим класс, который содержит различные методы и переменные. В этом классе есть некоторые методы, которые должны быть доступны только внутри класса, некоторые доступны только в пределах одного пакета, некоторые доступны в классах-наследниках, а некоторые должны быть доступны в любом месте программы. Вот здесь и начинают играть роль модификаторы доступа.
Private
Модификатор private делает члены класса (переменные, методы и т.д.) доступными только внутри самого этого класса. Они не будут доступны ни в пределах пакета, ни в классах-наследниках, ни где-либо ещё. Этот модификатор обычно используется для скрытия внутренней реализации класса.
Package-private (по умолчанию)
Если модификатор доступа не указан, то он считается package-private . Члены класса с таким модификатором доступа будут доступны только в пределах того же пакета. Это полезно, когда требуется разделить код на логические модули, но при этом дать доступ к некоторым составляющим модулю другим его частям.
Protected
Члены класса, помеченные модификатором protected , будут доступны в пределах того же пакета и во всех классах-наследниках, независимо от того, в каком пакете они находятся. Это обычно используется в ситуациях, когда нужно предоставить расширяемую функциональность в подклассах.
Public
Если член класса объявлен как public , он будет доступен в любом месте программы. Этот модификатор доступа часто используется для общедоступных методов и переменных, которые должны быть доступны везде.
Таким образом, выбор модификатора доступа зависит от того, где и как планируется использовать члены класса. Нужно внимательно продумать архитектуру программы и определить, какой уровень доступа необходим для каждого элемента класса.
Модификатор доступа protected и default не очень понятно
Если ничего не указывать, тогда будет стоять видимость по умолчанию - т.е. default.
Protected - "защищенный" - это видимость в границах пакета и видимость для классов-наследников. Можно сказать, что protected = default + наследование.
Отслеживать
ответ дан 19 ноя 2018 в 9:24
Петровченко Иван Петровченко Иван
1,893 1 1 золотой знак 12 12 серебряных знаков 36 36 бронзовых знаков
«Модификатор по умолчанию».
Если переменная или метод не помечены никаким модификатором, то считается, что они помечены «модификатором по умолчанию». Переменные и методы с таким модификатором видны всем классам пакета, в котором они объявлены, и только им. Этот модификатор еще называют «package» или «package private», намекая, что доступ к переменным и методам открыт для всего пакета, в котором находится их класс
Этот уровень доступа чуть шире, чем package. К переменной, методу или классу, помеченному модификатором protected, можно обращаться из его же пакета (как package), но еще из всех классов, унаследованных от текущего.
