Перейти к основному содержимому

«Защищенный» модификатор доступа Java

· 5 мин. чтения

1. Обзор

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

2. Защищенное ключевое слово

В то время как элементы, объявленные как частные , доступны только классу, в котором они объявлены, защищенное ключевое слово разрешает доступ из подклассов и членов того же пакета.

Используя защищенное ключевое слово, мы принимаем решения о том, какие методы и поля следует считать внутренними элементами пакета или иерархии классов, а какие доступны для внешнего кода.

3. Объявление защищенных полей, методов и конструкторов

Во-первых, давайте создадим `класс с именем FirstClass , содержащий защищенное` поле, метод и конструктор:

public class FirstClass {

protected String name;

protected FirstClass(String name) {
this.name = name;
}

protected String getName() {
return name;
}
}

В этом примере с помощью ключевого слова protected мы предоставили доступ к этим полям классам в том же пакете, что и FirstClass , и подклассам FirstClass .

4. Доступ к защищенным полям, методам и конструкторам

4.1. Из того же пакета

Теперь давайте посмотрим, как мы можем получить доступ к защищенным полям, создав новый GenericClass , объявленный в том же пакете, что и FirstClass :

public class GenericClass {

public static void main(String[] args) {
FirstClass first = new FirstClass("random name");
System.out.println("FirstClass name is " + first.getName());
first.name = "new name";
}
}

Поскольку этот вызывающий класс находится в том же пакете, что и FirstClass, ему разрешено видеть и взаимодействовать со всеми защищенными полями, методами и конструкторами.

4.2. Из другого пакета

Давайте теперь попробуем взаимодействовать с этими полями из класса, объявленного в пакете, отличном от FirstClass :

public class SecondGenericClass {

public static void main(String[] args) {
FirstClass first = new FirstClass("random name");
System.out.println("FirstClass name is "+ first.getName());
first.name = "new name";
}
}

Как мы видим, мы получаем ошибки компиляции :

The constructor FirstClass(String) is not visible
The method getName() from the type FirstClass is not visible
The field FirstClass.name is not visible

Именно этого мы и ожидали, используя защищенное ключевое слово. Это связано с тем, что SecondGenericClass не находится в том же пакете, что и FirstClass , и не является его подклассом.

4.3. Из подкласса

Давайте теперь посмотрим, что происходит, когда мы объявляем класс, расширяющий FirstClass , но объявленный в другом пакете :

public class SecondClass extends FirstClass {

public SecondClass(String name) {
super(name);
System.out.println("SecondClass name is " + this.getName());
this.name = "new name";
}
}

Как и ожидалось, мы можем получить доступ ко всем защищенным полям, методам и конструкторам. Это потому, что SecondClass является подклассом FirstClass .

5. защищенный внутренний класс

В предыдущих примерах мы видели защищенные поля, методы и конструкторы в действии. Есть еще один частный случай — защищенный внутренний класс.

Давайте создадим этот пустой внутренний класс внутри нашего FirstClass :

package com.foreach.core.modifiers;

public class FirstClass {

// ...

protected static class InnerClass {

}
}

Как мы видим, это статический внутренний класс, поэтому его можно создать извне экземпляра FirstClass . Однако, поскольку он защищен , мы можем создать его экземпляр только из кода в том же пакете, что и FirstClass .

5.1. Из того же пакета

Чтобы проверить это, давайте отредактируем наш GenericClass :

public class GenericClass {

public static void main(String[] args) {
// ...
FirstClass.InnerClass innerClass = new FirstClass.InnerClass();
}
}

Как мы видим, мы можем без проблем создать экземпляр InnerClass , потому что GenericClass находится в том же пакете, что и FirstClass .

5.2. Из другого пакета

Давайте попробуем создать экземпляр InnerClass из нашего SecondGenericClass , который, как мы помним, находится вне пакета FirstClass :

public class SecondGenericClass {

public static void main(String[] args) {
// ...

FirstClass.InnerClass innerClass = new FirstClass.InnerClass();
}
}

Как и ожидалось, мы получаем ошибку компиляции :

The type FirstClass.InnerClass is not visible

5.3. Из подкласса

Попробуем сделать то же самое из нашего SecondClass :

public class SecondClass extends FirstClass {

public SecondClass(String name) {
// ...

FirstClass.InnerClass innerClass = new FirstClass.InnerClass();
}
}

Мы ожидали, что с легкостью создадим экземпляр нашего InnerClass . Однако и здесь мы получаем ошибку компиляции:

The constructor FirstClass.InnerClass() is not visible

Давайте посмотрим на наше объявление InnerClass :

protected static class InnerClass {
}

Основная причина, по которой мы получаем эту ошибку, заключается в том, что конструктор по умолчанию защищенного класса неявно защищен . Кроме того, SecondClass является подклассом FirstClass, но не является подклассом InnerClass . Наконец, мы также объявили SecondClass вне пакета FirstClass .

По всем этим причинам SecondClass не может получить доступ к защищенному конструктору InnerClass .

Если бы мы хотели решить эту проблему и позволить нашему SecondClass создавать экземпляр объекта InnerClass , мы могли бы явно объявить общедоступный конструктор :

protected static class InnerClass {
public InnerClass() {
}
}

Делая это, мы больше не получаем ошибку компиляции, и теперь мы можем создать экземпляр InnerClass из SecondClass .

6. Заключение

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

Как всегда, код примера доступен на GitHub .