Влияние package на область видимости
Создаём 2 класса:
public class Base {
protected void method() {
System.out.println("Base");
}
}
public class Main extends Base {
public static void main(String[] args) {
Base obj = new Main();
obj.method();
}
@Override
public void method() {
System.out.println("Main");
}
}
Компилируем и запускаем https://onlinegdb.com/ByPbAtxZP, выводит:
Main
Теперь разносим их в разные пакеты (больше ничего не меняем):
package package1;
public class Base {
protected void method() {
System.out.println("Base");
}
}
package package2;
import package1.Base;
public class Main extends Base {
public static void main(String[] args) {
Base obj = new Main();
obj.method();
}
@Override
public void method() {
System.out.println("Main");
}
}
Пытаемся скомпилировать https://onlinegdb.com/SyCsAKxWw и получаем ошибку
Main.java:8: error: method() has protected access in Base obj.method(); ^
Почему после разделения на 2 пакета при попытке вызвать protected-метод базового класса происходит ошибка компиляции?
Ведь описании модификатора protected говорится
Поля и методы, обозначенные модификатором доступа
protected, будут видны:
- в пределах всех классов, находящихся в том же пакете, что и наш;
- в пределах всех классов-наследников нашего класса.
Ответы (1 шт):
Да, это кажется немного странным и объяснить это достаточно сложно. Я приведу несколько примеров, объясняющих такое поведение. Для начала сделаем так:
import package1.Base;
public class Main extends Base {
public static void main(String[] args) {
new Main().start();
}
public void start() {
super.method();
this.method();
}
@Override
protected void method() {
System.out.println("Main");
}
}
В этом случае в консоли мы видим Base Main (сначала отрабатывает метод суперкласса, а потом класса-наследника). Отсюда четко видно, что мы можем обратиться к protected методу родительского класса.
А теперь сделаем так:
import package1.Base;
public class Main extends Base {
public static void main(String[] args) {
new Main().start();
}
public void start() {
Main obj = new Main();
obj.method();//код компилируется
Base obj1 = new Main();
obj1.method(); //ошибка компиляции
}
@Override
protected void method() {
System.out.println("Main");
}
}
В первом случае вызов метода для Main obj = new Main() не вызывает проблем компиляции, а во втором для Base obj1 = new Main() мы видим ошибку.
Объясняется это тем, что protected метод доступен в одном пакете и для наследников (это видно в первом примере, где мы из другого пакета вызываем метод суперкласса). Во втором примере мы вызываем не метод суперкласса, а вызываем метод у переменной суперкласса (Base obj1 = new Main(); obj1.method(); - где obj1 - переменная типа суперкласса). Именно в этом кроется проблема.