Все компоненты класса в языке Java - поля, методы и конструкторы имеют модификаторы доступа. Модификаторы доступа управляют видимостью классов, методов и переменных, тем самым определяя, как к компонентам класса можно получить доступ из других частей программы. Они управляют тем, откуда можно получить доступ к конкретному классу, методу или переменной.
В Java используются следующие модификаторы доступа:
public: публичный, общедоступный класс или компонент класса. Поля и методы, объявленные с модификатором public, видны другим классам из текущего пакета и из внешних пакетов, вообще в любом месте программы.
Стоит отметить, что в исходном файле может быть только один класс с модификатором public, но количество классов с другими модификаторами (или без них) может быть любым. И если в файле есть класс с модификатором public, то имя файла должно совпадать с именем этого класса.
private: закрытый класс или компонент класса, противоположность модификатору public. Закрытый класс или компонент класса доступен только из кода в том же классе.
protected: такой класс или компонент класса доступен из любого места в текущем классе или пакете или в производных классах, даже если они находятся в других пакетах
Модификатор по умолчанию. Отсутствие модификатора у поля или метода класса предполагает применение к нему модификатора по умолчанию. Такие поля или методы видны всем классам в текущем пакете.
Вкратце модификаторы доступа можно суммировать в виде следующей таблицы:
Рассмотрим некоторые примеры применения модификаторов
Посмотрим на примере и создадим следующий класс State:
class State{
String defaultVar ="default"; // доступно в любом месте текущего пакета
private String privateVar = "private"; // доступно только из текущего класса
protected String protectedVar = "protected"; // доступно из текущего пакета и производных классов
public String publicVar = "public"; // доступно в любом месте программы
// доступен в любом месте текущего пакета
void printDefault() { System.out.println(defaultVar); }
// доступен только из текущего класса
private void printPrivate() { System.out.println(privateVar); }
// доступен из текущего пакета и производных классов
protected void printProtected() { System.out.println(protectedVar); }
// доступен в любом месте программы
public void printPublic() { System.out.println(publicVar);}
}
Так как класс State не имеет явного модификатора, поэтому он будет доступен из любого места данного пакета, однако не будет доступен из других пакетов.
Класс State имеет четыре поля для каждого уровня доступа. А также определено 4 методов с разными модификаторами, которые выводят значения соответствующих переменных на консоль. Поскольку все модификаторы позволяют использовать компоненты класса внутри данного класса, то и все переменные класса, в том числе закрытые, у нас доступны всем его методам, так как все находятся в контексте класса State.
Теперь посмотрим, как мы сможем использовать переменные класса State в другом классе, который расположен в том же пакете:
class Program {
public static void main(String[] args) {
State state = new State();
// переменная defaultVar с модификатором по умолчанию доступна из любого места текущего пакета
// поэтому можно получить или изменить ее значение
System.out.println(state.defaultVar); //Ошибка, получить доступ нельзя
// обратиться к переменной privateVar у нас не получится,
// так как она имеет модификатор private и класс Program ее не видит
System.out.println(state.privateVar); // Ошибка, получить доступ нельзя
// переменная protectedVar так же доступна из любого места текущего пакета
// (а также в производных классах других пакетов)
System.out.println(state.protectedVar);
// переменная publicVar общедоступна везде
System.out.println(state.publicVar);
}
}
class State{
String defaultVar ="default"; // доступно в любом месте текущего пакета
private String privateVar = "private"; // доступно только из текущего класса
protected String protectedVar = "protected"; // доступно из текущего пакета и производных классов
public String publicVar = "public"; // доступно в любом месте программы
// доступен в любом месте текущего пакета
void printDefault() { System.out.println(defaultVar); }
// доступен только из текущего класса
private void printPrivate() { System.out.println(privateVar); }
// доступен из текущего пакета и производных классов
protected void printProtected() { System.out.println(protectedVar); }
// доступен в любом месте программы
public void printPublic() { System.out.println(publicVar);}
}
Таким образом, в классе Program мы смогли только обратиться к переменным defaultVar, protectedVar и publicVar, так как их модификаторы позволяют использовать в данном контексте.
Аналогично дело обстоит и с методами:
class Program {
public static void main(String[] args) {
State state = new State();
state.printDefault(); // норм
state.printPrivate(); // Ошибка, получить доступ нельзя
state.printProtected(); // норм
state.printPublic(); // норм
}
}
class State{
String defaultVar ="default"; // доступно в любом месте текущего пакета
private String privateVar = "private"; // доступно только из текущего класса
protected String protectedVar = "protected"; // доступно из текущего пакета и производных классов
public String publicVar = "public"; // доступно в любом месте программы
// доступен в любом месте текущего пакета
void printDefault() { System.out.println(defaultVar); }
// доступен только из текущего класса
private void printPrivate() { System.out.println(privateVar); }
// доступен из текущего пакета и производных классов
protected void printProtected() { System.out.println(protectedVar); }
// доступен в любом месте программы
public void printPublic() { System.out.println(publicVar);}
}
Здесь нам оказались доступны только три метода: printDefault, printProtected, printPublic, которые имееют соответственно модификатор по умолчанию и модификаторы protected и public.
Теперь мосмотрим, что будет, если классы State и Program расположены в разных пакетах. Допустим, у нас есть проект со следующей структурой:
Файл Program.java
Папка types
Файл State.java
Пусть файл State.java будет содержать определение аналогичного класса State:
package types;
public class State{
String defaultVar ="default"; // доступно в любом месте текущего пакета
private String privateVar = "private"; // доступно только из текущего класса
protected String protectedVar = "protected"; // доступно из текущего пакета и производных классов
public String publicVar = "public"; // доступно в любом месте программы
// доступен в любом месте текущего пакета
void printDefault() { System.out.println(defaultVar); }
// доступен только из текущего класса
private void printPrivate() { System.out.println(privateVar); }
// доступен из текущего пакета и производных классов
protected void printProtected() { System.out.println(protectedVar); }
// доступен в любом месте программы
public void printPublic() { System.out.println(publicVar);}
}
Здесь только два отличие по сравнению с предыдущим определением класса State:
Класс State принадлежит пакету "types" (поэтому и располагается в соответствующем каталоге)
Класс State определен с модификатором public, благодаря чему он виден из других пакетов
Применим этот класс в классе Program:
import types.State;
class Program {
public static void main(String[] args) {
State state = new State();
state.printDefault(); // Ошибка
state.printPrivate(); // Ошибка
state.printProtected(); // Ошибка
state.printPublic(); // норм
}
}
И здесь мы видим, что мы можем обратиться только к тем полям класса, которые имеют модификатор public. То же самое касается методов, пример с которыми я не буду приводить, так как все аналогично.