【问题标题】:Why an instance of inherited class can't access to protected member of base class in different package为什么继承类的实例无法访问不同包中基类的受保护成员
【发布时间】:2014-03-07 23:41:53
【问题描述】:

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

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

谁能解释我上面代码中每个错误的原因?

谢谢:)

【问题讨论】:

  • 这是因为 C 没有扩展 B。可见性不具有传递性。

标签: java


【解决方案1】:

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

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

对于C 类,您无法访问B 的任何受保护成员,因为您既不继承自B,也不与B 在同一个包中。

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

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

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

      但您的问题是,您正试图访问与this 不同的对象的受保护成员。看看这个http://bmanolov.free.fr/javaprotection.php

      【讨论】:

        【解决方案4】:

        我认为JLS 6.6.2.1 给出了答案:

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

        另外,如果Id表示实例字段或实例方法,那么:

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

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

        您正在访问B 正文中的成员value。因此,为了应用这个子句,S 是B,并且根据最后一段,当您尝试访问某个表达式 E 的 E.value 时,只有当 E 的类型是 B 或 B 的子类时才允许访问. 由于类型是 A,它不是 B 的子类,所以这个条件不成立。

        【讨论】:

          猜你喜欢
          • 2018-10-21
          • 2014-02-22
          • 2015-06-09
          • 2013-03-05
          • 2018-02-11
          • 2019-01-20
          • 2012-08-29
          • 2016-10-01
          相关资源
          最近更新 更多