13

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

它是这样的:

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

4 回答 4

7

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

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

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

对象的受保护成员或构造函数可以从包外部访问,在该包中,仅由负责实现该对象的代码声明它。

于 2013-04-03T23:01:51.110 回答
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 = 2JLS 6.2.2.1

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

请注意,它没有说直接子类,而只是说子类。所以a = 2B班级或C班级内工作。

另一方面,ancient.a = 2;由同一部分中的下一个要点介绍:

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

在您的情况下,Q.Idis ancient.a=> 只有在 is 的ancient类型BB. 例如,这将编译:

public class B extends A{
     public void accessField() {
        C ancient = new C();
        ancient.a = 2;  //A - That wouldn't work.
     }
}
于 2013-04-03T23:22:51.760 回答
1

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

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

于 2013-04-03T23:17:36.680 回答
0

引用JLS 6.6.2

对象的受保护成员或构造函数可以从包外部访问,在该包中,仅由负责实现该对象的代码声明它。

当你说,

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

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

a = 2;

如果,

ancient.a = 2;

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

于 2013-04-03T23:31:40.467 回答