我知道在此论坛之前已经提到过这个问题,但我会再次提问,因为我没有看到任何好的答案(到目前为止)。
这就是:
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中对超类对象古代访问的这种限制背后的理性是什么? 感谢。
答案 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.Id
为ancient.a
=>只有ancient
的类型为B
或B
的子类时,才能访问它。例如,这将编译:
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)
对象的受保护成员或构造函数可以从包外部访问,只能通过负责实现该对象的代码来声明它。
当你说,
A ancient = new A();
ancient.a = 2;
你不是从古代(一个对象)继承任何东西,因此不负责它的实现。通过使 C扩展A ,您已经从另一个A对象继承了'a',因此下面的语句可以工作。
a = 2;
如果,
ancient.a = 2;
有效,那么公共访问说明符和私有访问说明符之间没有区别。