Java: защищенный доступ через пакеты
Я хотел бы понять, что происходит в примере ниже (где защищенный член получает доступ извне пакета через подкласс).
Я знаю для классов вне пакета, подкласс может видеть защищенный член только через наследование.
Существует два пакета: package1
и package2
.
-
package1
: ProtectedClass.java
package org.test.package1;
public class ProtectedClass {
protected void foo () {
System.out.println("foo");
}
}
-
package2
: ExtendsprotectedClass.java
package org.test.package2;
import org.test.package1.ProtectedClass;
public class ExtendsprotectedClass extends ProtectedClass {
public void boo() {
foo(); // This works,
// since protected method is visible through inheritance
}
public static void main(String[] args) {
ExtendsprotectedClass epc = new ExtendsprotectedClass();
epc.foo(); // Why is this working?
// Since it is accessed through a reference,
// foo() should not be visible, right?
}
}
-
package2
: UsesExtendedClass.java
package org.test.package2;
public class UsesExtendedClass {
public static void main(String[] args) {
ExtendsprotectedClass epc = new ExtendsprotectedClass();
epc.foo(); // CompilationError:
// The method foo() from the type ProtectedClass
// is not visible
}
}
Понятно, что метод boo()
в ExtendsprotectedClass
может получить доступ к foo()
, так как защищенные члены могут быть доступны только через наследование.
Мой вопрос: почему метод foo()
работает нормально при доступе через ссылку в методе main()
ExtendsprotectedClass
, но не будет работать при обращении через ссылку epc
в UsesExtendedClass
?
Ответы
Ответ 1
Код в классе ExtendsprotectedClass
имеет доступ к защищенным членам ProtectedClass
через ссылку типа ExtendsprotectedClass
. Из JLS раздел 6.6.2:
Защищенный член или конструктор объекта может быть доступен извне пакета, в котором он объявляется только кодом, ответственным за реализацию этого объекта.
и
Пусть C - класс, в котором объявлен защищенный член m. Доступ разрешен только внутри тела подкласса S of C. Кроме того, если Id обозначает поле экземпляра или метод экземпляра, то:
- Если доступ осуществляется по квалифицированному имени Q.Id, где Q является именем ExpressionName, то доступ разрешен тогда и только тогда, когда тип выражения Q является S или подклассом S. [...]
UsesExtendedClass
не является неприемлемым для реализации ExtendsprotectedClass
, поэтому окончательный вызов не выполняется.
РЕДАКТИРОВАНИЕ: аргументация заключается в том, что доступ protected
предназначен для того, чтобы помочь подклассам реализовать те функции, которые им нужны, что дает больший доступ к внутренним элементам суперкласса, чем обычно доступно. Если бы это было доступно для всего кода, это было бы довольно близко к тому, чтобы сделать этот метод общедоступным. В принципе, подклассам доверяют не нарушать инкапсуляцию; они получают больше возможностей внутри объектов своего типа. Открытый API не должен раскрывать эти данные, но защищенный API может только для того, чтобы предоставить подклассам больше возможностей.
Ответ 2
Он работает в первом случае, потому что он вызывается из того же класса, даже к способу обращается через ссылку. Вы даже можете вызвать метод private
ExtendsprotectedClass
через ссылку в том же основном методе.
Ответ 3
Я считаю, что вы ответили на свой вопрос; UsesExtendedClass не наследуется от ProtectedClass, а по определению - защищенные члены доступны только в классе, в котором они объявлены/определены или в классе, который наследует тот, в котором они объявлены или определены.
Ответ 4
взгляните на это изображение: http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
![enter image description here]()
ясно, что доступ к защищенному члену класса можно получить через подкласс.