Java:跨包的受保护访问

2022-09-04 03:10:40

我想了解下面的示例中发生了什么(通过子类从包外部访问受保护成员)。

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

有两个包:和 。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
        }
    }
    

可以理解的是,中的方法可以访问 ,因为受保护的成员只能通过继承来访问。boo()ExtendsprotectedClassfoo()

我的问题是,为什么通过方法中的引用访问该方法时,该方法工作正常,但通过方法中的引用访问时将不起作用foo()main()ExtendsprotectedClassepcUsesExtendedClass


答案 1

允许类中的代码通过 类型的引用访问 的受保护成员。来自 JLS 第 6.6.2 节ExtendsprotectedClassProtectedClassExtendsprotectedClass

可以从包外部访问对象的受保护成员或构造函数,在该包中,仅由负责实现该对象的代码声明该对象。

设 C 是声明受保护成员 m 的类。只允许在 C 的子类 S 的主体内访问。此外,如果 Id 表示实例字段或实例方法,则:

  • 如果访问是通过限定名 Q.Id(其中 Q 是 ExpressionName)进行的,则当且仅当表达式 Q 的类型为 S 或 S 的子类时,才允许访问。

UsesExtendedClass不负责 实现 ,因此最终调用失败。ExtendsprotectedClass

编辑:这背后的原因是,访问旨在帮助子类实现它们所需的功能,从而提供对超类内部的更多访问,而不是通常可用的。如果这适用于所有代码,那么它将非常接近于公开该方法。基本上,子类被信任不会破坏封装;它们在自己类型的对象中被赋予了更多功能。公共 API 不应公开这些详细信息,但受保护的 API 可以仅用于为子类提供更多机会。protected


答案 2

它在第一种情况下是有效的,因为它是从同一类调用的,即使通过引用访问该方法也是如此。您甚至可以在同一主方法中通过引用调用的方法。privateExtendsprotectedClass


推荐