【问题标题】:Java: protected access across packagesJava:跨包的受保护访问
【发布时间】:2011-04-02 05:21:12
【问题描述】:

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

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

有两个包: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(),因为受保护的成员只能通过继承来访问。

我的问题是,为什么当通过ExtendsprotectedClassmain() 方法中的引用访问时foo() 方法工作正常,但通过epc 引用访问时不起作用UsesExtendedClass?

【问题讨论】:

    标签: java inheritance packages protected


    【解决方案1】:

    ExtendsprotectedClass 类中的代码可以通过ExtendsprotectedClass 类型的引用访问ProtectedClass 的受保护成员。来自JLS section 6.6.2

    对象的受保护成员或构造函数可以从包外部访问,只有负责实现该对象的代码才能在该包中对其进行声明。

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

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

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

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

    【讨论】:

    • @Jon 谢谢。我知道子类的类成员可以访问受保护的成员(如boo() 方法中所示)。但是很想知道为什么允许通过子类的引用访问受保护的成员,ONLY 在子类方法中?有什么理由吗?
    • 2) 之所以有效,是因为受保护的方法是由其自己的类的指针访问的。这应该会失败:
      public static void ExtendsprotectedClass.main(String[] args){ ProtectedClass epc = new ExtendsprotectedClass(); //upcast
      epc.foo(); // 应该是编译错误?
      }
    • @Jon: 完全同意protected 访问旨在帮助子类实现他们需要的功能。这就是为什么我添加了一个sn-p代码boo()调用foo()。即子类代码可以使用受保护的foo()或覆盖基类的foo()。了解。但我仍然没有得到的是为什么它允许通过引用直接访问ExtendsprotectedClass epc = new ExtendsprotectedClass();epc.foo();。它不应该像第二种情况那样正确?为什么它允许通过引用访问受保护方法foo() 的任何理由只在实现基类的类中?
    • @JWhiz:因为这意味着该类中的代码能够轻松地处理自身的实例——例如比较、静态工厂方法等。仅仅编写一个实例方法可能会很痛苦为了能够接触到特定的成员。同样,子类的代码应该知道它在做什么。
    • @Jon :您能否提供指向示例代码的指针,其中通过引用实现基类的同一类的引用来访问同一类的私有/受保护方法。接受这个作为答案..
    【解决方案2】:

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

    【讨论】:

    • by definition -- "protected" members are accessible only in the class in which they are declared / defined。我不太同意这一点,因为受保护的成员可以从同一个包中的其他类访问而无需继承。
    【解决方案3】:

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

    【讨论】:

    • 谢谢。现在我明白了为什么它能够通过引用访问它。 +1 为它。但是,不应该允许通过对象引用来调用private 方法吗?这是否违反了制作它的目的 private ?允许这样做的任何具体原因?
    • @JWhiz java 访问修饰符在类而不是实例级别工作。因此,私有方法对类来说是私有的,而不是实例。如果 private 在实例上工作,如果两个实例必须交互,则必须将更多变量和方法设为 public。这会通过使实现在类外部可见而破坏封装。
    【解决方案4】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-02-03
      • 1970-01-01
      • 1970-01-01
      • 2012-09-27
      • 2010-10-18
      • 2013-04-03
      • 1970-01-01
      相关资源
      最近更新 更多