Java:跨包的受保护访问
我想了解下面示例中发生的情况(通过子类从包外部访问受保护的成员)。
我知道对于包外的类,子类只能通过inheritance来查看受保护的成员。
有两个包: 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 } }
可以理解, ExtendsprotectedClass
中的boo()
方法可以访问foo()
,因为受保护的成员只能通过inheritance来访问。
我的问题是,为什么foo()
方法在通过ExtendsprotectedClass
的main()
方法中的引用访问时工作正常,但在通过UsesExtendedClass
的epc
引用访问时UsesExtendedClass
?
允许ExtendsprotectedClass
类中的代码通过ExtendsprotectedClass
类型的引用访问ProtectedClass
保护成员。 从JLS部分6.6.2 :
受保护的成员或对象的构造函数可以从包外部访问,只能通过负责实现该对象的代码来声明它。
和
设C是声明受保护成员m的类。 仅允许在C的子类S的主体内进行访问。此外,如果Id表示实例字段或实例方法,则:
- 如果访问是通过限定名称Q.Id,其中Q是ExpressionName,那么当且仅当表达式Q的类型是S或S的子类时才允许访问。[…]
UsesExtendedClass
不适用于ExtendsprotectedClass的实现,因此最终调用失败。
编辑:这背后的原因是protected
访问旨在帮助子类实现他们需要的function,从而提供比通常可用的超类内部更多的访问权限。 如果所有代码都可以使用它,那么将该方法公之于众。 基本上,子类被信任不破坏封装; 他们在自己类型的对象中获得了更多的能力。 公共API不应公开这些细节,但受保护的API只能用于为子类提供更多机会。
它在第一种情况下工作,因为它是从同一个类调用的,即使通过引用访问该方法。 您甚至可以通过同一main方法中的引用调用ExtendsprotectedClass
的private
方法。
我相信你已经回答了自己的问题; UsesExtendedClass不从ProtectedClassinheritance,并且 – 根据定义 – “protected”成员只能在声明/定义它们的类中或从inheritance它们的声明或定义的类中访问。
看看这张图片来自: http : //docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
很明显,类的受保护成员可以通过子类访问。