Java: cannot access a protected member of the supe

2019-01-25 13:44发布

问题:

I want some discussions about this, but I could not infer the answer for my case. Still need help.

Here is my code:

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

    }
}

Some definitions following which, the example above seems to be confusing:

 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.

The question: Why can't I access the protected member (int variable = 5) from a subclass YetAnotherClass instance (bill object)?

回答1:

Classes in other packages that are subclasses of the declaring class can only access their own inherited protected members.

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

... but not other objects' inherited protected members.

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


回答2:

bill is not part of the subclassed YetAnotherClass. bill is a separate YetAnotherClass.

Try int bill = this.variable; (inside a constructor) to access the subclass' members.



回答3:

Your code will work if YetAnotherClass will be in the same package as ATypeNameProgram. As others wrote it won't work in other cases. Here is the working example.

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:

A class Foo can only access the protected instance members of type Bar if and only if Bar is assignable to Foo. I.e., if we can write:

Foo foo = new Bar(); 

For example, say we have:

package a;

public class Base {
    protected int protectedField;
}

Then we can have this:

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 { }

This will compile because all protectedFields are accessed via instances of Parent. Note that because a Parent reference can be a Child instance (i.e., we can write Parent p = new Child();), we can access c.protectedField.

The following will not compile:

package b;

import a.Base;

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

class Stepchild extends Base {}

because an instance of Stepchild is not an instance of Parent.

Somewhat confusingly, this won't compile either:

package b;

import a.Base;

public class Parent extends Base {}

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

this is because a Parent object isn't a superclass or superinterface of Child, and so Child can't access its protected members.

If you ever have trouble remembering, just think of whether or not the type can be written to a reference of the type of the class. E.g., we can write:

Parent p = new Child();

but cannot write

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

so Child won't have access to Parent's protected members, and Parent won't have access to Stepchild's protected members.

A couple final points:

Remember that protected access allows visibility among the package. In my experience, people forget this.

Finally, protected static members are always visible among the inheritance hierarchy.



回答5:

You aren't creating an instance of the class that extend it, but of the parent class. Check the code below:

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

    }
}