Модификаторы доступа в Java - Вопросы
Всего: 5 вопросов
1. Сколько в Java модификаторов доступа и сколько уровней доступа?
Сколько в Java модификаторов доступа и сколько уровней доступа?
Модификаторов доступа три — public, protected и private, а уровней доступа четыре. Четвёртый уровень, package-private (уровень доступа по умолчанию), не имеет собственного ключевого слова: он получается, когда модификатор не указан вообще.
Откуда виден член класса на каждом уровне:
public— из любого кода, который видит сам класс;protected— из всего своего пакета и дополнительно из классов-наследников в других пакетах (через ссылку типа наследника);- package-private — только из кода в том же пакете;
private— только внутри тела своего класса верхнего уровня, включая его вложенные классы.
Уровни строго упорядочены по строгости: private → package-private → protected → public. Начиная с Java 9 поверх них работает модульная система JPMS: public-класс не виден из другого модуля, если его пакет не экспортирован директивой exports.
2. Что открывает модификатор protected и почему вызов other.protectedAccessMethod() внутри Child не компилируется?
package oop.p2;
import oop.p1.Parent;
public class Child extends Parent {
public void compare(Parent other, Child sibling) {
this.protectedAccessMethod();
super.protectedAccessMethod();
sibling.protectedAccessMethod();
other.protectedAccessMethod();
}
}
Что открывает модификатор protected и почему вызов other.protectedAccessMethod() внутри Child не компилируется?
package oop.p2;
import oop.p1.Parent;
public class Child extends Parent {
public void compare(Parent other, Child sibling) {
this.protectedAccessMethod();
super.protectedAccessMethod();
sibling.protectedAccessMethod();
other.protectedAccessMethod();
}
}protected делает две вещи сразу: открывает член всем классам своего пакета (как package-private) и дополнительно наследникам в других пакетах. То есть он строго шире package-private, а распространённая формулировка «protected — это для наследников» неполна: класс AccessClass, лежащий рядом с Parent в пакете oop.p1, вызывает protectedAccessMethod() вообще без наследования.
Последняя строка не компилируется из-за отдельного правила спецификации языка (JLS 6.6.2.1): из наследника в другом пакете обращаться к protected-члену можно только через выражение, тип которого — сам этот наследник или его подтип. У this, super и sibling тип Child, поэтому эти три вызова корректны; other объявлен как Parent, и компилятор его отклоняет.
Смысл ограничения: наследник получает право работать со своей унаследованной частью объекта, а не со всеми объектами родительского типа в системе.
3. Какие уровни доступа применимы к классу верхнего уровня в Java?
Какие уровни доступа применимы к классу верхнего уровня в Java?
Только два из четырёх: public и package-private. Модификаторы private и protected к классу верхнего уровня применить нельзя — компилятор выдаст ошибку. А вложенному классу доступны все четыре уровня, потому что он является членом внешнего класса.
Если сам класс не виден, недоступно ничего внутри него, включая public-члены. Попытка обратиться к package-private классу HotBeverage из другого пакета падает уже на строке import:
package oop.p1;
class HotBeverage {
}
package oop.p2;
// import oop.p1.HotBeverage; // Ошибка компиляции: класс не public
public class Tea {
// extends HotBeverage - невозможно из другого пакета
}
И правило про файлы: public-класс должен быть единственным public-типом верхнего уровня в файле, а имя файла обязано совпадать с именем класса. Рядом с ним можно объявить сколько угодно package-private классов — но это независимые классы верхнего уровня, и private-члены друг друга они не видят:
// файл Beverage.java
public class Beverage {
}
class HotBeverage {
}
class ColdBeverage {
}
4. Можно ли при переопределении метода сузить уровень доступа?
Можно ли при переопределении метода сузить уровень доступа?
Нет. При переопределении уровень доступа можно сохранить или расширить, но не сузить: package-private поднимается до protected или public, protected — до public. Попытка сузить даёт ошибку компиляции «attempting to assign weaker access privileges».
package oop.p1;
public class Child extends Parent {
@Override
public void hook() { // OK: доступ расширен с protected до public
}
// @Override
// void hook() {} // Ошибка: попытка ослабить доступ
}
Причина — принцип подстановки Лисков: код, работающий с переменной типа Parent, обязан иметь возможность вызвать hook(), какой бы конкретный наследник туда ни подставили.
С private-методом история другая: он не наследуется и потому не переопределяется вообще. Метод с той же сигнатурой в наследнике — это просто новый, независимый метод, и аннотация @Override на нём вызовет ошибку компиляции.
5. Какие модификаторы доступа имеют члены интерфейса в Java?
Какие модификаторы доступа имеют члены интерфейса в Java?
В интерфейсах действуют свои правила:
- абстрактные методы неявно
public abstract, а поля — неявноpublic static final; - писать
publicу метода интерфейса разрешено, но избыточно и обычно считается лишним шумом. Отсутствиеpublicне делает метод package-private — он всё равноpublic; - с Java 8 в интерфейсе можно объявлять
default- иstatic-методы с телом (ключевое словоdefaultздесь про реализацию по умолчанию, а не про уровень доступа); - с Java 9 в интерфейсе разрешены
private-методы — для вынесения общего кода изdefault-методов.
Итог: единственный уровень доступа, который реально выбирается внутри интерфейса, — private для вспомогательного метода; всё, что входит в контракт, — public.