【问题标题】:Java : Protected access restriction for subclass on superclass objectJava:超类对象上子类的受保护访问限制
【发布时间】:2013-03-25 20:22:04
【问题描述】:

我知道这个论坛以前有人问过这个问题,但我会再问一次,因为我没有看到任何好的答案(到目前为止)。

这里是:

package a;
public class A{
    protected int a;
}

package b;
public class B extends A{
}

package c;
public class C extends B{
    public void accessField(){
        A ancient = new A();
        ancient.a = 2;  //A - That wouldn't work.

        a = 2;   //B - That works.
    }

}

为什么条款 A) 不起作用?在子类 C 中限制超类对象古代访问的原因是什么?
谢谢。

【问题讨论】:

  • 我想这里的一个继承步骤对于说明这种情况是多余的。
  • @HovercraftFullOfEels 我想这个问题是理论多于实际但并非无趣。

标签: java


【解决方案1】:

如果是通过继承,则只能在同一个包之外访问受保护的成员 - 即在层次结构内。

因此,当您从不同的包创建 A 的另一个实例时,这不是继承关系,因此会失败。

与往常一样,这在 JLS 6.6.2 中有所介绍:

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

【讨论】:

  • 我很困惑。同一部分还说“仅允许在 C 的子类 S 的主体内访问。” - 它没有说 直接 子类,只是子类...跨度>
  • @assylias 公平点 - 在这种情况下,这不是我所说的直接的意思,但我知道它可能会模棱两可,所以我稍微改变了措辞!
【解决方案2】:

实际上你不需要两个层次的继承,下面的代码会导致相同的行为:

public class B extends A{
     public void accessField() {
        A ancient = new A();
        ancient.a = 2;  //A - That wouldn't work.

        a = 2;   //B - That works.
    }
}

a = 2起作用的原因是JLS 6.2.2.1

令 C 为声明受保护成员的类。只允许在 C 的子类 S 的主体内访问。

注意它没有说direct子类,而只是子类。所以a = 2B 类或C 类中工作。

另一方面,ancient.a = 2; 包含在同一部分的下一个要点中:

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

在您的情况下,Q.Idancient.a => 只有在 ancient 的类型是 BB 的子类时才能访问它。例如,这将编译:

public class B extends A{
     public void accessField() {
        C ancient = new C();
        ancient.a = 2;  //A - That wouldn't work.
     }
}

【讨论】:

    【解决方案3】:

    引用《Java 编程语言 3 版》一书。由 Gosling 等人撰写 - 第 81 页 sec 3.5

    “受保护的真正含义” - .. 除了可以在类本身中访问以及在同一个包中进行代码之外,受保护的成员还可以通过对象引用从类中访问至少与类相同的类型 - 即类的类型或其子类之一的引用

    【讨论】:

      【解决方案4】:

      引用JLS 6.6.2

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

      当你说,

      A ancient = new A();
      ancient.a = 2;
      

      您没有从古代(A 对象)继承任何东西,因此不对其实施负责。通过使 C 扩展 A,您已经从不同的 A 对象继承了“a”,因此下面的语句有效。

      a = 2;
      

      如果,

      ancient.a = 2;
      

      有效,那么公共访问说明符和私有访问说明符之间没有区别。

      【讨论】:

        猜你喜欢
        • 2012-12-01
        • 2013-05-27
        • 1970-01-01
        • 2013-06-08
        • 2015-05-09
        • 2017-12-09
        • 2014-05-14
        • 2011-02-18
        • 2012-06-02
        相关资源
        最近更新 更多