Private в языке java

Обзор всех модификаторов в Java

Модификаторы это ключевые слова в Java, которые «изменяют и регулируют» работу классов, методов и переменных.

Все члены класса в языке Java имеют модификаторы. Модификаторы — это ключевые слова, которые «изменяют и регулируют» работу классов, методов и переменных.

В Java множество различных модификаторов, но они не имеют строгой структуры. Однако, из всех модификаторов принято выделять «модификаторы доступа». Их мы рассмотрим в самом конце.

Прочие модификаторы

Начнём наш разбор с модификаторов, которые нельзя объединить в какую-то группу. Этакие модификаторы одиночки 🙂

Модификатор final

С английского «final» можно перевести как «последний, окончательный». Этот модификатор тем или иным образом защищает от изменений переменные, методы и классы.

Переменная final

Переменная объявленная как final после инициализации становится неизменной. Это значит, что примитив изменить не выйдет, а для ссылочной переменной не удастся присвоить новую ссылку на другой объект.

Для final переменных на уровне класса значение устанавливается сразу или через конструктор.

public class Foo < private final int a = 10; private final Bar bar; public Foo(Bar bar) < this.bar = bar; >> class Bar

В примере выше переменную a мы устанавливаем сразу, а переменную bar в конструкторе.

Изменить значения этих переменных не выйдет (строка 13 и 14). Однако данные внутри объекта могут быть изменены (строка 16). Таким образом, состояние полей объекта, на который ссылается final переменная, изменяемо.

Аргументы и локальные переменные метода также могут быть final . Тогда изменить их тоже не выйдет (строки 4, 5).

public void method(final int a) < final long b = 10; a = 10; // error b = 20; // error >

Помните, что final переменную класса объявляют сразу или в конструкторе. Но на локальную переменную метода это правило не распространяется. Вы можете объявить её, но не инициализировать до момента ее использования.

Такое поведение позволяет инициализировать final переменную по условию. Например, так:

public void method(int a) < final long b; if (a >10) < b = 20; >else < b = 30; >b = 50; // error >

Метод final

Для методов final означает запрет на переопределение в наследниках.

class Foo < final void method() < System.out.println("test"); >> class Bar extends Foo < final void method() < // error System.out.println("test"); >>

Это полезно, когда вы допускаете использование класса в наследовании, но поведение конкретного метода хотите запретить переопределять.

Класс final

Применение final по отношению к классу объявляет класс завершённым — запрещает дальнейшее наследование от такого класса.

final class Foo < >class Bar extends Foo < // error >

Модификатор static

Обычный подход в Java — это создать класс, потом создать экземпляр класса, то есть объект, и вызывать метод класса у этого объекта.

С использованием модификатора static объявляются методы и переменные, которые не нуждаются в объекте класса. Таким образом, методы и переменные вызываются от класса, а не от объекта.

Этот модификатор не получится применить к конструктору, а также к обычному классу, но к вложенному классу применить static можно.

package p1; class Foo < static String field = "Test"; static String getString() < return "Test two"; >> class Main < public static void main(String[] args) < System.out.println(Foo.field); System.out.println(Foo.getString()); > >

Вы можете вызывать static методы и переменные от объекта, но делать так не рекомендуется. Если мы говорим про объекты, то каждый объект обладает полями, которые содержат уникальные значения. Изменяя поле у одного объекта класса, мы не повлияем на поля другого объекта того же класса. Если вы измените static поле, то оно изменится у всех экземпляров класса.

Также у вас не получится сделать наследника, так как при наследовании вызывается конструктор класса родителя.

Зачем нужен такой конструктор?

Может показаться, что это бред. Зачем тогда нужен такой класс? Выделяют два случая, когда такой конструктор оказывается полезным.

Первый — это статические фабричные методы для создания объекта. О них мы говорили в разделе модификатора static . Таким образом, мы скрываем конструктор и оставляем только фабричные методы.

public class Foo < private Foo(int a) < >public static Foo of(int a) < return new Foo(a); >public static Foo doubleCreate(int a) < return new Foo(a * a); >>

Второй случай — это создание утилитарных классов, также упоминаемые раньше. Обычно вы не хотите, чтобы кто-то создавал объекты таких классов, так как это не имеет никакого смысла.

Класс private

Обратите внимание, что перед самим Foo стоит модификатор доступа public . Поставить private попросту не выйдет. Однако, мы сможем поставить модификатор private у вложенного класса:

Метод private

Приватный метод невозможно вызвать из другого класса.

class Foo < private void privateMethod() < >public void method() < >> class Bar < void method(Foo foo) < foo.method(); // success foo.privateMethod(); // error >>

Приватные методы недоступны для вызова даже у наследника.

class Foo < private void privateMethod() < >> class ChildFoo < void method() < this.privateMethod(); // error >>

Не имеет смысла объявлять метод private final так как private метод не виден в наследниках, соответственно не может быть предопределен.

Переменная private

Повторяет особенности private-метода: у других классов, в том числе у наследников, нет доступа к этому полю.

Модификатор доступа default-package

Особенностью этого модификатора — отсутствие ключевого слова. Если вы не указываете модификатор, то он применяется по умолчанию.

С таким модификатором доступ есть внутри этого класса, а также все классы, которые находятся в этом пакете, имеют доступ.

Рассмотрим пример использования. У нас есть класс Foo и Bar в одном пакете p1 и класс DifferentPackage в другом пакете.

package p1; public class Foo < int defaultField; Foo(int i, int i2) < >void defaultMethod() < >>
package p1; public class Bar < public void testMethod(Foo foo) < foo.defaultField = 2; // success foo.defaultMethod(); // success foo = new Foo(1); // success >>

В случае с классом Bar никаких ошибок не будет, мы сможем получить доступ и к конструктору, и к методу, и к полю. Но если мы попробуем то же самое сделать в классе DifferentPackage , то столкнёмся с ошибками.

package p2; public class DifferentPackage < public void testMethod(Foo foo) < foo.defaultField = 2; // error foo.defaultMethod(); // error foo = new Foo(1); // error >>

Модификатор доступа protected

Этот модификатор доступа обладает свойствами модификаторов private и default-package . А также позволяет наследникам обращаться к членам класса родителя.

Посмотрим на примере. У нас есть класс Foo в пакете p1 и пакет p2 с классом наследником ChildFoo и классом DifferentPackage .

package p1; public class Foo < protected int defaultField; protected Foo(int i) < >protected void defaultMethod() < >>

C классом DifferentPackage всё так же, как и в прошлом примере. А для ChildFoo теперь есть доступ к полям/методам/конструктору своего родителя.

package p2; import p1.Foo; public class ChildFoo extends Foo < protected ChildFoo(int i) < super(i); >void method() < System.out.println(defaultField); defaultMethod(); >>

Также необходимо у ChildFoo реализовать конструктор, который будет вызывать конструктор родителя.

Модификатор доступа public

Этот модификатор позволяет обращаться к членам класса откуда угодно. Если это переменная, то любой класс из любого пакета может её прочитать и изменить. Если это метод, то любой класс может его вызывать. Если это конструктор, то любой класс может его вызвать.

Шпаргалка для модификаторов доступа переменной

Визуально модификаторы доступа переменной класса можно представить таким образом:

Резюмирую

Модификаторы неотъемлемая базовая составляющая языка Java. Без полного понимания работы всех модификаторов будет сложно продолжать изучать этот язык.

Помните, не ко всем членам класса можно применять тот или иной модификатор. А также, что не все они сочетаются друг с другом.

Отдельным особняком стоят модификаторы доступа. Они позволяют вам защищать члены классов от модификации извне, тем самым реализуя один из принципов ООП — Инкапсуляцию.

Источник

Private в языке 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), так как с их помощью мы получаем значение поля.

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

Источник

Читайте также:  Python desktop application example
Оцените статью