Java:跨包的 protected 访问

标签 java inheritance package protected

我想了解下面示例中发生的情况(通过子类从包外部访问 protected 成员)。

我知道对于包外的类,子类只能通过继承才能看到 protected 成员。

有两个包:package1package2

  1. package1:ProtectedClass.java

    package org.test.package1;
    
    public class ProtectedClass {
    
        protected void foo () {
            System.out.println("foo");
        }
    }
    
  2. 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?
        }
    }
    
  3. 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成员只能通过继承访问.

我的问题是,当通过 ExtendsprotectedClassmain() 方法中的引用访问时,为什么 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/

相关文章:

Clojure 中的 Java 输入(读取行)在 Emacs 中无法正确读取

java - 如何使用 javaFx TriangleMesh 创建这样的形状?

java - 我放入 res/drawable 文件夹中的 PNG 将不会显示在代码中

c# - C# 应该有多重继承吗?

android: 错误解析包

r - 使用 roxygen2 导入两个同名函数

即使使用复制本地集,Azure 包也不包括链接的项目 DLL

java - 从 token 过滤器调用时未注入(inject) Autowiring 服务

c++ - 检测方法是否被覆盖

c++ - 如果仅存在私有(private)函数,则访问基类中的私有(private)数据类型