【问题标题】:Java: cannot access a protected member of the superclass in the extending subclassJava:无法在扩展子类中访问超类的受保护成员
【发布时间】:2013-06-08 03:13:22
【问题描述】:

我想对此进行一些讨论,但我无法为我的案例推断出答案。仍然需要帮助。

这是我的代码:

package JustRandomPackage;

public class YetAnotherClass{
    protected int variable = 5;
}
package FirstChapter;

import JustRandomPackage.*;

public class ATypeNameProgram extends YetAnotherClass{
    public static void main(String[] args) {

        YetAnotherClass bill = new YetAnotherClass();
        System.out.println(bill.variable); // error: YetAnotherClass.variable is not visible

    }
}

下面的一些定义,上面的例子似乎令人困惑:

 1. Subclass is a class that extends another class.
 2. Class members declared as protected can be accessed from 
    the classes in the same package as well as classes in other packages 
    that are subclasses of the declaring class.

问题:为什么我不能从子类YetAnotherClass 实例(bill 对象)访问受保护的成员(int variable = 5)?

【问题讨论】:

  • 问题是什么?

标签: java protected


【解决方案1】:

作为声明类子类的其他包中的类只能访问它们自己继承的protected 成员。

package FirstChapter;

import JustRandomPackage.*;

public class ATypeNameProgram extends YetAnotherClass{
    public ATypeNameProgram() {
        System.out.println(this.variable); // this.variable is visible
    }
}

...但不是其他对象的继承protected 成员。

package FirstChapter;

import JustRandomPackage.*;

public class ATypeNameProgram extends YetAnotherClass{
    public ATypeNameProgram() {
        System.out.println(this.variable); // this.variable is visible
    }

    public boolean equals(ATypeNameProgram other) {
        return this.variable == other.variable; // error: YetAnotherClass.variable is not visible
    }
}

【讨论】:

  • 这是错误的。此代码编译。另一个包中的类只能访问与该类本身具有相同类型的继承的受保护成员。
  • 这里应该将构造函数参数的类型从 ATypeNameProgram 更改为 YetAnotherClass ,以便解释正确。
【解决方案2】:

当且仅当Bar 可分配给Foo 时,类Foo 才能访问类型为Bar 的受保护实例成员。即,如果我们可以写:

Foo foo = new Bar(); 

例如,假设我们有:

package a;

public class Base {
    protected int protectedField;
}

那么我们可以有这个:

package b;

import a.Base;

public class Parent extends Base {
    void foo() {
        int i = this.protectedField;
    }
    void foo(Parent p) {
        int i = p.protectedField;
    }
    void foo(Child c) {
        int i = c.protectedField;
    }
}

class Child extends Parent { }

这将编译,因为所有protectedFields 都是通过Parent 的实例访问的。请注意,因为Parent 引用可以是Child 实例(即,我们可以写为Parent p = new Child();),所以我们可以访问c.protectedField。

以下将不编译:

package b;

import a.Base;

public class Parent extends Base {
    void foo(Stepchild sc) {
        int i = sc.protectedField; // ERROR
    }
}

class Stepchild extends Base {}

因为Stepchild 的实例不是Parent 的实例。

有点令人困惑,这也不会编译:

package b;

import a.Base;

public class Parent extends Base {}

class Child extends Parent {
    void foo(Parent p) {
        p.protectedField; // ERROR
    }
}

这是因为Parent 对象不是Child 的超类或超接口,因此Child 无法访问其受保护的成员。

如果你记忆困难,想想是否可以将类型写入类类型的引用。例如,我们可以这样写:

Parent p = new Child();

但不能写

Child c = new Parent();     // ERROR
Parent p = new Stepchild(); // ERROR

所以Child 将无权访问Parent 的受保护成员,而Parent 将无权访问Stepchild 的受保护成员。

最后几点:

请记住,protected 访问允许包之间的可见性。根据我的经验,人们会忘记这一点。

最后,protected static 成员在继承层次结构中始终可见。

【讨论】:

    【解决方案3】:

    如果YetAnotherClass 与ATypeNameProgram 在同一个包中,您的代码将起作用。正如其他人所写,它在其他情况下不起作用。这是工作示例。

    package my.example;
    
    public class MainClass extends MyAnotherClass {
        public static void main(String[] args) {
            MyAnotherClass bill = new MyAnotherClass();
            System.out.println(bill.value); // this will work
        }
    }
    
    package my.example;
    
    public class MyAnotherClass {
    
        protected int value = 5;
    
    }
    

    【讨论】:

      【解决方案4】:

      您不是在创建扩展它的类的实例,而是创建父类的实例。检查下面的代码:

      public class ATypeNameProgram extends YetAnotherClass{
          public static void main(String[] args) {
      
              YetAnotherClass bill = new YetAnotherClass();
              System.out.println(bill.variable); // error: YetAnotherClass.variable is not visible
      
              ATypeNameProgram a = new ATypeNameProgram();
              System.out.println(a.variable); //this will work
      
          }
      }
      

      【讨论】:

        【解决方案5】:

        bill 不是子类 YetAnotherClass 的一部分。 bill 是一个单独的 YetAnotherClass。

        尝试int bill = this.variable;(在构造函数中)访问子类的成员。

        【讨论】:

        • 没错!很好地抓住了@mcalex。他正在制作超类的对象,而不是子类...显然我的受保护变量有问题。
        猜你喜欢
        • 2011-02-18
        • 2012-12-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-16
        • 2013-10-21
        • 1970-01-01
        • 2016-02-29
        相关资源
        最近更新 更多