Защищенный доступ членов из разных пакетов в java - любопытство

package packageOne;
public class Base
{
protected void display(){
system.out.println("in Base");
}
}


package packageTwo;
public class Derived extends packageOne.Base{
public void show(){
new Base().display();//this is not working throws compilation error that display() from the type Base is not visible
new Derived().display();//is working
display();//is working
}
}

Два пакета находятся в двух разных файлах. Но почему это поведение?

Ответы

Ответ 1

http://java.sun.com/docs/books/jls/third_edition/html/names.html#6.6

class C
    protected member;

// in a different package

class S extends C 

    obj.member; // only allowed if type of obj is S or subclass of S

Мотивация, вероятно, следующая. Если obj является S, класс S обладает достаточным знанием своих внутренних элементов, он имеет право манипулировать своими членами, и он может сделать это безопасно.

Если obj не является S, возможно, это еще один подкласс S2 of C, о котором S не имеет понятия. S2, возможно, даже не родился, когда написано S. Для S для управления защищенными внутренними элементами S2 довольно опасно. Если это разрешено, с точки зрения S2, он не знает, кто будет вмешиваться в его защищенные внутренние компоненты и как это делает труд S2 очень трудным для рассуждения о своем собственном состоянии.

Теперь, если obj есть D и D extends S, опасно ли для S получить доступ к obj.member? На самом деле, нет. Как S использует member является общим знанием S и всех его подклассов, включая D. S, поскольку суперкласс имеет право определять поведение и D, поскольку подкласс обязан принять и согласовать.

Для более легкого понимания правило должно быть действительно упрощено, чтобы потребовать obj (статический) тип в точности S. В конце концов, очень необычно и неуместно, чтобы подкласс D появился в S. И даже если это произойдет, что статический тип obj равен D, наше упрощенное правило может легко справиться с этим повышением: ((S)obj).member

Ответ 2

protected позволяет получить доступ из подклассов и других классов в одном пакете. Поэтому любой экземпляр класса Derived может получить доступ к защищенному методу в Base.

Другая строка создает экземпляр Base (не экземпляр Derived!). И доступ к защищенным методам этого экземпляра разрешен только для объектов одного и того же пакета.


display();

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

new Derived().display();

- > разрешено, потому что вы вызываете метод в экземпляре Derived, и этот экземпляр имеет доступ к защищенным методам своих подклассов

new Base().display();

- > не разрешено, поскольку класс вызывающего (класса this) не определен в том же пакете, что и класс Base, поэтому this не может получить доступ к защищенному методу. И не имеет значения - как мы видим, - что текущий подкласс представляет класс из этого пакета. Этот бэкдор закрыт;)

Ответ 3

Защищенный доступ имеет некоторые специальные правила, которые подробно описаны в Спецификация языка Java:

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

Ответ 4

new Base().display();

Он создает базовый объект, а затем пытается вызвать дисплей() на нем.
Очевидно, что это не сработает, потому что экран() на базе защищен.

Ответ 5

Это предполагаемое поведение. protected означает, что унаследованные классы и те же классы пакетов могут видеть этот метод. Итак, это то, что вы видите.

Ответ 6

Это может быть прямой ответ на ваш вопрос, но я не вижу причин, по которым вы бы назвали новый Base().display();. Возможно, вы имеете в виду super.display();.

В этом случае вы на самом деле используете унаследованный метод, но только потому, что вы наследуете класс, это не означает, что вы обращаетесь к защищенным методам class (которые по определению являются только для суперклассов).

Разница заключается в одном случае (ваш пример), который вы пытаетесь получить доступ к защищенному методу из экземпляра класса, который вы унаследовали. В моем примере вы можете получить доступ к защищенному методу через наследование.

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

Почему?

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

Ответ 7

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

Ответ 8

display не является статическим методом внутри Base. Итак, вы должны сначала создать экземпляр Base, а затем вызвать отображение.

Base base = new Base();
base.display();