Java:超类对象上子类的受保护访问限制

时间:2013-04-03 22:57:47

标签: java

我知道在此论坛之前已经提到过这个问题,但我会再次提问,因为我没有看到任何好的答案(到目前为止)。

这就是:

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中对超类对象古代访问的这种限制背后的理性是什么? 感谢。

4 个答案:

答案 0 :(得分:7)

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

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

与往常一样,这在JLS,6.6.2:

中有所涉及
  

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

答案 1 :(得分:5)

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

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 = 2适用于B类或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.
     }
}

答案 2 :(得分:1)

引用书籍Java编程语言3编辑。作者:Gosling et all - 第81秒3.5

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

答案 3 :(得分:0)

引自JLS 6.6.2

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

当你说,

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

你不是从古代(一个对象)继承任何东西,因此不负责它的实现。通过使 C扩展A ,您已经从另一个A对象继承了'a',因此下面的语句可以工作。

a = 2;

如果,

ancient.a = 2;

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