我想了解下面示例中发生的情况(通过子类从包外部访问 protected 成员)。
我知道对于包外的类,子类只能通过继承才能看到 protected 成员。
有两个包: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()
,因为protected成员只能通过继承访问.
我的问题是,当通过 ExtendsprotectedClass
的 main()
方法中的引用访问时,为什么 foo()
方法工作正常但是当通过 UsesExtendedClass
中的 epc
引用访问时将不起作用?
最佳答案
ExtendsprotectedClass
类中的代码可以通过 ExtendsprotectedClass
类型的引用访问 ProtectedClass
的 protected 成员。来自JLS section 6.6.2 :
A protected member or constructor of an object may be accessed from outside the package in which it is declared only by code that is responsible for the implementation of that object.
和
Let C be the class in which a protected member m is declared. Access is permitted only within the body of a subclass S of C. In addition, if Id denotes an instance field or instance method, then:
- If the access is by a qualified name Q.Id, where Q is an ExpressionName, then the access is permitted if and only if the type of the expression Q is S or a subclass of S. [...]
UsesExtendedClass
不负责 ExtendsprotectedClass
的实现,因此最终调用失败。
编辑:这背后的原因是 protected
访问旨在帮助子类实现他们需要的功能,提供比通常可用的更多的父类(super class)内部访问权限。如果这对所有 代码都可用,那么将非常接近公开该方法。基本上,子类被信任不会破坏封装;他们在自己类型的对象中被赋予了更多的能力。公共(public) API 不应该公开这些细节,但 protected API 可以只是为了给子类更多机会。
关于Java:跨包的 protected 访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3540640/