使用子类引用访问包外的受保护成员

Posted

技术标签:

【中文标题】使用子类引用访问包外的受保护成员【英文标题】:Accessing protected members outside package with child class reference 【发布时间】:2018-10-30 05:33:14 【问题描述】:
package pack1;
class A
   protected void m1()
      System.out.println("protected modifier");
   


package pack2;
class B extends A
    public static void main(string[]args)
         B b = new B();//Valid
         b.m1();

        A a = new B();//Invalid
          a.m2();

       A a1 = new A();//InValid
         a1.m1();

   

为什么在访问包外的受保护成员时,我们只需要子类引用。?

为什么我们不能使用父引用来访问受保护的成员(这里 A a = new B())?

我浏览了博客和许多堆栈溢出的答案,但没有找到 WHY? 的任何答案。

那么任何人都可以帮助我知道为什么的答案吗?

【问题讨论】:

您不能访问A,因为您仍然子类或包之外。 main 方法是static,因此未绑定B 类的实例。为了访问A,您需要 B 类中,所以在非静态上下文中。 Java : Protected access restriction for subclass on superclass object的可能重复 @Zabuza 你能详细说明你的答案吗?对我来说还不清楚 【参考方案1】:

您不能访问A,因为您仍然子类或包之外。 main 方法是 static,因此与 B 类的实例未绑定。为了访问A,您需要 B 类中,所以在非静态上下文中,例如

public class B extends A 
    public void foo() 
        m1(); // Valid call since inside subclass
    

我认为你误解了static 的含义。


Java 语言规范 中描述了protected 的详细信息。摘自JLS§6.6.2:

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

C 成为声明protected 成员的类。 仅允许在 C 的子类 S 的主体内访问

限制甚至超出了您的示例。关键是“负责实施”。将其与以下示例进行比较:

package a;

public class Point 
    protected int x;
    protected int y;

package b;

import a.Point;

public class Point3D extends Point 
    public void delta(Point other) 
        other.x += this.x;  // Compile-time error: Cannot access other.x
        other.y += this.y;  // Compile-time error: Cannot access other.y
    

虽然Point3D 类是Point 的子类,但它不负责other 对象的实现。因此,不允许访问其protected 成员。

同样

public class B extends A 
    public void foo() 
        A other = new A();
        other.m1(); // Compile-time error
    

由于foo()方法调用所属的当前实例不负责other的实现。因此,不允许访问。

【讨论】:

那是错误的。您的最后一次通话 new A().m1(); 无效,并给您一个错误:The method m1() from the type A is not visible。您不允许从 B 访问受保护的方法 A.m1(),除非您在 B 类型的实例上调用它。无论您是否处于静态上下文中,您都不能从 B 内部调用 new A().m1() @ErwinBolwidt 这是正确的。出于与上一个示例完全相同的原因。如 JLS 段落所述,关键是“负责实施”。 @Zabuza,“Point3D 是 Point 的子类,它不负责 p 对象的实现”..如果 Point3D 不负责提供实现,那么根据你谁负责? @sainathpawar 这是关于Point3D 的当前实例。不是班级本身。假设您有一个类Person,那么您可以有多个实例,例如johnjane。而john 实例不负责janes 的东西。因此,不允许他访问janes protected 成员。只有jane 被允许这样做。而john只对自己的protected成员负责,所以只能访问。【参考方案2】:

继承/多态的概念使得父类的继承的公共和受保护的方法和变量——子类的成员,因此可以被子类的对象访问。受保护的访问需要两个规则-

    只能被同一个包内的类访问

    可以通过继承访问。

    A a = 新 B();

    a.m1(); //不编译

这是 B 类的一个实例,但就它是 A 的引用而言,它是一个 A 对象。这就是为什么对象“a”只能访问 A 和 B 共有的成员。即对象“a”作为类 A 的引用只能访问类 B 的继承方法。它无权访问任何B 的方法或类变量在 A 中不存在,即使它是 B 类的实例。您必须将其显式转换为 B 以使其访问 B 类的唯一方法和变量。因此,请记住这一点,就 Java 而言,对象“a”是另一个包中的类 A 对象。因此,即使方法 a.m1 被继承,“a”也无法访问它,因为它是另一个包中的 A 对象。 a.m1 将在 pack1 中编译。

与此代码对比

B b = new B();
b.m1() //compiles

b 是 B 的对象,因此适用受保护访问的规则 2。由于 m1 是对象 B 的一个继承的受保护方法,因此它可以完全访问它。

【讨论】:

以上是关于使用子类引用访问包外的受保护成员的主要内容,如果未能解决你的问题,请参考以下文章

Java中的间接子类无法访问的超类中的受保护成员

访问另一个子类中基类的受保护成员

在父类的子类中访问静态类的受保护成员

如何防止基类的受保护成员仍然在子类的第二级被访问?

C++ 派生模板类:访问实例的受保护成员

Java - 子类中的受保护变量是啥类型?