Защищенный доступ членов из разных пакетов в 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();