为什么继承类的实例无法访问不同包中基类的受保护成员

3

我有三个类A、B和C:

package com.training.protectedclass.A;

public class A
{
    protected int   value;
}

package com.training.protectedclass.B;
import com.training.protectedclass.A.A;

public class B extends A
{
    public void test()
    {
        this.value = 10;
        A a = new A();
        a.value = 12; //Error => The field A.value is not visible
    }
}

package com.training.protectedclass.C;

import com.training.protectedclass.B.B;
import com.training.protectedclass.A.A;

public class C extends A
{
    public void test()
    {           
        B b = new B();
        b.value = 45; //Error => The field A.value is not visible
    }
}

当继承类存在于与基类不同的包中时,它无法访问基类的受保护成员。但是当所有三个类都存在于同一包中时,上述错误消失,代码将被编译而没有错误。
有人能解释一下我代码中发生的每个错误的原因吗?
谢谢 :)

3
这是因为 C 没有继承 B,可见性不具有传递性。 - Isaiah van der Elst
4个回答

3
这是因为在Java中,protected有两种含义:1)继承的类可以看到它们继承的受保护成员,2)同一包中的其他类也可以看到受保护的成员(即使它们没有继承该成员)。
所以在B类中,你已经继承了value,因此可以通过this.value访问它,但由于A类在另一个包中,所以你无法看到a.value。这是因为当你调用a.value时,你正在访问另一个包中的类的成员,而不是字段value的继承版本。
C类的情况下,你既没有从B继承,也不在与B相同的包中,因此无法访问B的任何受保护成员。

1

Java语言规范这样定义protected访问修饰符:

对象的protected成员或构造函数只能被负责实现该对象的代码从其声明的包外部访问。

当你有this.value = 10;时,B对象访问其自身的一个成员,该成员是在超类中声明的protected字段。另一方面,当你有new A().value时,B对象试图访问其未实现的对象的protected成员。


1

1

我认为JLS 6.6.2.1给出了答案:

假设一个受保护成员在类C中声明。只有在子类S的主体内才允许访问。

此外,如果Id代表实例字段或实例方法,则:

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

如果通过字段访问表达式E.Id(其中E是Primary表达式)或通过方法调用表达式E.Id(...)(其中E是Primary表达式)进行访问,则仅当E的类型为S或S的子类时才允许访问。

您正在B的主体中访问成员value。因此,对于应用此条款,S是B,根据最后一段内容,当您尝试访问某个表达式E的E.value时,只有当E的类型为B或B的子类时才允许访问。由于类型为A,不是B的子类,因此此条件失败。

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