无法访问一个既是子类又是子类的受保护成员

3
这是一份关于IT技术的翻译内容。以下是需要翻译的文本:

这是一个例子,来自 Java程序员认证指南——第三版——Khalid A. Mughal Rolf W. Rasmussen,我无法理解。

我知道如果我们没有将受保护成员(protected member)继承到另一个包中定义的子类中,就无法访问它。

但我仍然不明白为什么我们不能从子类的子类中访问它。

以下是例子:

A.java

package packageA;
public class A {
    protected int z;
}

B.java

package packageB;

import packageA.A;

public class B extends A {

    void action(A obj1, B obj2, C obj3) {
        z = 10;      // z in B - Works
        obj1.z = 10; // Won't work for obvious reason
        obj2.z = 10; // z in B - Works
        obj3.z = 10; // z in C - Works

    }
}

class C extends B {

    void action(A obj1, B obj2) {
        z = 10; // Works
        obj1.z = 10; // Won't work for obvious reason
        obj2.z = 10; // z in B - WHY DOESN'T THIS WORK?????

    }
}

这是一项学术练习还是你真的想要写出这样的代码? - jiggy
@jiggy 这是《Java程序员认证指南(第三版)》一书中的一个例子,我无法理解。 - Cengiz Can
我肯定希望作者不要使用诸如“A”、“B”等类名来举例。如果他们这样做的话,就不是很直观了! - Joeblackdev
2个回答

3
当前被接受的答案并没有回答这个问题。它解释了为什么你不能在BC的主体中访问实例A的成员z。但问题是为什么你不能在C内部访问实例B的成员z。原因是B不是C的子类。请阅读Java规范第6.6.2.1节。
让C成为声明受保护成员的类。只有在子类S的主体内才允许访问。此外,如果Id表示实例字段或实例方法,则:如果通过限定名称Q.Id进行访问,其中Q是ExpressionName,则仅当表达式Q的类型为S或S的子类时,才允许访问。在B中,您可以说obj3.z,因为obj3的类型为C,而C是B的子类。http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6.2.1(我加粗了)所述。

但是在 C 中,您不能说 obj2.z,因为 obj2 的类型是 B,而 B 不是 C 的子类。


总结protected的含义: 假设一个受保护的成员在类A的主体内声明。
(1) 你可以从包含A的任何位置访问受保护的成员。
(2) 此外,在不同包中定义的A的子类S可以在S的实例或继承自S的类的实例上访问受保护的成员,但不能在S继承的类的实例上访问。
当回答这个问题时,最后一条是关键点。

1

受保护的成员只能被声明在其内的类的子类或同一包中的类访问。在您的情况下,B和C不是与A在同一个包中声明的类。这就是为什么您无法通过对类A的引用来访问'z'。如果将类B和C移动到与A相同的包中,则可以使用它。

这就是为什么您无法在类C中访问obj2.z,因为'z'是在不同包中声明的类中声明的。


这是否意味着成员访问在第二个子类中不会被继承? - Cengiz Can
我想我不能像编译器一样思考。 - Cengiz Can
1
如果你正在学习SCJP(就像我一样),当你看到一个受保护的成员时,应该想到“包和子类”来访问。换句话说,只有子类和同一包中的类才能访问受保护的成员,没有例外。祝你学习顺利。 - Joeblackdev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接