14

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

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

有两个包:package1package2

  1. package1ProtectedClass.java

    package org.test.package1;
    
    public class ProtectedClass {
    
        protected void foo () {
            System.out.println("foo");
        }
    }
    
  2. package2ExtendsprotectedClass.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. package2UsesExtendedClass.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
        }
    }
    

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

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

4

4 回答 4

12

允许类中的代码通过 type 的引用ExtendsprotectedClass访问受保护的成员。从JLS 部分 6.6.2ProtectedClassExtendsprotectedClass

对象的受保护成员或构造函数只能由负责实现该对象的代码从声明它的包外部访问。

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

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

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

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

于 2010-08-22T07:57:16.150 回答
2

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

于 2010-08-22T09:23:03.067 回答
1

我相信您已经回答了自己的问题;UsesExtendedClass 不从 ProtectedClass 继承,并且——根据定义——“受保护”成员只能在声明/定义它们的类或从声明或定义它们的类继承的类中访问。

于 2010-08-22T07:58:55.297 回答
0

看看这张图片来自:http ://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html

在此处输入图像描述

很明显,可以通过子类访问受保护的类成员。

于 2014-04-30T20:19:26.490 回答