Public java что это
Все члены класса в языке Java — поля и методы — имеют модификаторы доступа. В прошлых темах мы уже сталкивались с модификатором public . Модификаторы доступа позволяют задать допустимую область видимости для членов класса, то есть контекст, в котором можно употреблять данную переменную или метод.
В Java используются следующие модификаторы доступа:
- public : публичный, общедоступный класс или член класса. Поля и методы, объявленные с модификатором public, видны другим классам из текущего пакета и из внешних пакетов.
- private : закрытый класс или член класса, противоположность модификатору public. Закрытый класс или член класса доступен только из кода в том же классе.
- protected : такой класс или член класса доступен из любого места в текущем классе или пакете или в производных классах, даже если они находятся в других пакетах
- Модификатор по умолчанию . Отсутствие модификатора у поля или метода класса предполагает применение к нему модификатора по умолчанию. Такие поля или методы видны всем классам в текущем пакете.
Рассмотрим модификаторы доступа на примере следующей программы:
public class Program < public static void main(String[] args) < Person kate = new Person("Kate", 32, "Baker Street", "+12334567"); kate.displayName(); // норм, метод public kate.displayAge(); // норм, метод имеет модификатор по умолчанию kate.displayPhone(); // норм, метод protected //kate.displayAddress(); // ! Ошибка, метод private System.out.println(kate.name); // норм, модификатор по умолчанию System.out.println(kate.address); // норм, модификатор public System.out.println(kate.age); // норм, модификатор protected //System.out.println(kate.phone); // ! Ошибка, модификатор private >> class Person < String name; protected int age; public String address; private String phone; public Person(String name, int age, String address, String phone)< this.name = name; this.age = age; this.address = address; this.phone = phone; >public void displayName() < System.out.printf("Name: %s \n", name); >void displayAge() < System.out.printf("Age: %d \n", age); >private void displayAddress() < System.out.printf("Address: %s \n", address); >protected void displayPhone()< System.out.printf("Phone: %s \n", phone); >>
В данном случае оба класса расположены в одном пакете — пакете по умолчанию, поэтому в классе Program мы можем использовать все методы и переменные класса Person, которые имеют модификатор по умолчанию, public и protected. А поля и методы с модификатором private в классе Program не будут доступны.
Если бы класс Program располагался бы в другом пакете, то ему были бы доступны только поля и методы с модификатором public.
Модификатор доступа должен предшествовать остальной части определения переменной или метода.
Инкапсуляция
Казалось бы, почему бы не объявить все переменные и методы с модификатором public , чтобы они были доступны в любой точке программы вне зависимости от пакета или класса? Возьмем, например, поле age, которое представляет возраст. Если другой класс имеет прямой доступ к этому полю, то есть вероятность, что в процессе работы программы ему будет передано некорректное значение, например, отрицательное число. Подобное изменение данных не является желательным. Либо же мы хотим, чтобы некоторые данные были достуны напрямую, чтобы их можно было вывести на консоль или просто узнать их значение. В этой связи рекомендуется как можно больше ограничивать доступ к данным, чтобы защитить их от нежелательного доступа извне (как для получения значения, так и для его изменения). Использование различных модификаторов гарантирует, что данные не будут искажены или изменены не надлежащим образом. Подобное сокрытие данных внутри некоторой области видимости называется инкапсуляцией .
Так, как правило, вместо непосредственного применения полей используют методы доступа. Например:
public class Program < public static void main(String[] args) < Person kate = new Person("Kate", 30); System.out.println(kate.getAge()); // 30 kate.setAge(33); System.out.println(kate.getAge()); // 33 kate.setAge(123450); System.out.println(kate.getAge()); // 33 >> class Person < private String name; private int age = 1; public Person(String name, int age)< setName(name); setAge(age); >public String getName() < return this.name; >public void setName(String name) < this.name = name; >public int getAge() < return this.age; >public void setAge(int age) < if(age >0 && age < 110) this.age = age; >>
И затем вместо непосредственной работы с полями name и age в классе Person мы будем работать с методами, которые устанавливают и возвращают значения этих полей. Методы setName, setAge и наподобие еще называют мьютейтерами (mutator), так как они изменяют значения поля. А методы getName, getAge и наподобие называют аксессерами (accessor), так как с их помощью мы получаем значение поля.
Причем в эти методы мы можем вложить дополнительную логику. Например, в данном случае при изменении возраста производится проверка, насколько соответствует новое значение допустимому диапазону.
Модификаторы 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 , 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
- Задания
Области видимости и модификаторы доступа
Область видимости переменной, метода или класса – это их свойство быть доступными из тех или иных частей кода, т. е. различных областей программы. Область видимости может определяться как самим местом объявления идентификатора, так и применением к нему модификатора доступа.
Отдельно следует отметить модификатор static, который регулирует не область видимости, а обозначает статические переменные и методы, которые существуют без необходимости создания объекта, обращаться к ним следует через имя класса. Статические переменные существуют все время работы программы, однако это не мешает регулировать область их видимости модификаторами доступа.
Если переменная объявляется в теле метода, в цикле или условной конструкции, то она исчезает после завершения работы метода, цикла или ветки. То же самое касается аргументов методов, переменные-аргументы существуют только в момент выполнения метода. Следовательно, такие локальные переменные не могут быть доступными из других блоков кода. Модификаторы доступа здесь не используются.
Переменные-поля и методы (не статические) объекта существуют только в период жизни этого объекта. При этом их область видимости регулируется модификаторами. Классы существуют всегда, к ним также применяются модификаторы доступа, но не все.
В программах на языке Java часто используют два модификатора доступа – public и private. Реже – protected. Кроме того, есть так называемый модификатор по умолчанию, который используется, когда не указан ни один другой.
Если к полю, методу или классу применен модификатор public, к ним можно обращаться из любого места программы. То есть public-сущности доступны любым другим классам как в текущем пакете, так и за его пределами. Данное положение не отменяет необходимости импорта пакета.
Модификатор private применяется к переменным или методам, по отношению к классам не имеет смысла. К таким private-сущностям можно обращаться только из того же класса, где они объявлены. Для всех остальных классов, в том числе дочерних, такие поля и методы остаются невидимыми.
Если никакой модификатор не используется, считается, что используется модификатор по умолчанию. Классы, поля или методы с таким модификатором видны всем классам пакета, в котором они объявлены. Другими словами, видны в пределах текущего каталога.
Модификатор protected схож с модификатором по умолчанию, за одним исключением. Поля и методы доступны не только в пределах пакета, но и в классах-наследниках, т. е. производных классах, даже если они находятся в другом пакете.
Таким образом степень приватности увеличивается так: public → protected → default → private.
Рассмотрим пример. Файл Main.java:
public class Main public static void main(String[] args) Book a = new Book("The Way", -50); System.out.println(a.getTitle()); System.out.println(a.getPage()); > >
class Book private String t; private int p; Book(String title, int page) this.t = title; this.p = testPage(page); > String getTitle() return this.t; > int getPage() return this.p; > private int testPage(int pg) if (pg > 0) return pg; else return -pg; > >
Оба файла находятся в одном каталоге, т. е. принадлежать одному пакету. Поэтому в классе Book можно не использовать модификатор public, чтобы предоставить доступ к Book классу Main. Метод testPage может использоваться только внутри класса Book.
Если бы в каталог, где находятся Main.java и Book.java, был вложен другой каталог-пакет с классами, то эти классы должны были бы иметь модификатор public для доступа к ним из Main.
Таким образом, классы в Java могут иметь модификатор public, либо не иметь явно указанного модификатора. У полей и методов может быть один из четырех, считая модификатор по умолчанию. Однако объявление публичного метода в непубличном классе вряд ли имеет смысл.
Также не следует забывать про модификатор static, который, если используется, пишется после модификатора доступа. Следом указывается тип переменной или возвращаемое методом значение. Далее идут имя переменной или метода. Если метод ничего не возвращает используется ключевое слово void.
X Скрыть Наверх
Программирование на Java. Курс
