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

时间:2014-03-07 23:41:54

标签: java

我有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
    }
}

当继承的类存在于与基类不同的包中时,它无法访问基类的受保护成员。但是当所有三个类都存在于同一个包中时,上述错误就会消失,并且代码编译时没有错误。

有人能解释一下我在上面的代码中启动的每个错误的原因吗?

谢谢:)

4 个答案:

答案 0 :(得分:3)

这是因为Java中的protected意味着两件事:1)继承的类可以看到它们继承的受保护成员,2)同一个包中的其他类可以看到受保护的成员(即使它们不继承会员)。

因此,在课程B中,您继承了value,因此您可以通过this.value访问它,但由于课程A位于另一个包中,您无法看到{ {1}}。这是因为当您调用a.value时,您正在访问另一个包中的类的成员而不是字段a.value的继承版本。

对于课程value,您无法访问C的任何受保护成员,因为您既不从B继承,也不在与B相同的包中

答案 1 :(得分:1)

Java Language Specification以这种方式定义受保护的访问修饰符:

  

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

当你有this.value = 10;时,B对象访问它自己的一个成员,这是一个在超类中声明的受保护字段。另一方面,当您有new A().value时,B对象会尝试访问它未实现的对象的受保护成员。

答案 2 :(得分:1)

http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html中的文档说明了这一点。

  

protected修饰符指定只能访问该成员   在它自己的包中(与package-private一样),另外,通过   另一个包中其类的子类。

但问题是,您正在尝试访问与this不同的对象的受保护成员。检查一下http://bmanolov.free.fr/javaprotection.php

答案 3 :(得分:1)

我认为JLS 6.6.2.1给出了答案:

  

设C是声明受保护成员的类。访问是   只允许在C的子类S的主体内使用。

     

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

     

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

     

如果访问是通过字段访问表达式E.Id,其中E是a   主表达式,或方法调用表达式E.Id(...),   其中E是主表达式,如果和,则允许访问   只有当E的类型是S或S的子类时。

您正在访问value正文中的成员B。因此,对于应用此子句,S为B,并且根据最后一段,当您尝试访问某些表达式E的E.value时,仅当E的类型为B或B的子类。由于类型是A,它不是B的子类,因此该条件失败。