Eclipse shows an error when trying to use protecte

2020-03-26 03:39发布

问题:

Hello Stackoverflow community :-]

I am a new member and first I would like to thank you for the very helpful advice and correction that you provide. As I am french, please forgive me if my english is not perfect.

Here is my question : I'm currently learning Java programming language, and I wanted to test some inheritance stuff. If I understood right, a field declared as protected can be accessed by classes which are in the same package as the class where protected field is declared, and by all of its subclasses, whether they are in the same package or not.

So, I did these 4 classes to test this. I have a package named "package1" containing classes A and C. I also have a second package named "package 2" containing classes A2 and C, where A2 extends A. The two C classes have exactly the same code, just the package where they are located changes.They do not extend A.

In A class, I declared some members with different access properties, especially the constructor which is declared with protected visibility. Here is the code of the four classes.

package1, class A :

package package1;

public class A {

    public int a;
    protected int b;
    private int c;
    int d;

    protected static int h = 30;

    protected void aff(){
        System.out.println(h);
    }

    protected A(){
        a = 1;
        b = 2;
        c = 3;
        d = 4;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub

    }

}

package 1, class C :

package package1;

public class C {

    public C(){
        super();
    }

    public void app(){
        A obj = new A(); //////// OK
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub


        A obj = new A(); //////// OK
        obj.aff(); //////// OK

        System.out.println(obj.a);

    }

}

package2, class A2 (extends A) :

package package2;
import package1.A;

public class A2 extends A{

    public int x;

    A2(){
        super();
    }


    public void app(){
        A obj = new A(); //////// ERROR
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub


        A obj = new A(); //////// ERROR

        A2 obj2 = new A2();
        obj2.aff(); //////// OK



    }

}

package2, class C :

package package2;
import package1.A;

public class C {


    public C(){
        super();
    }

    public void app(){

        A obj = new A(); //////// ERROR
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub


        A obj = new A(); //////// ERROR
        obj.aff(); //////// ERROR

        System.out.println(obj.a);

    }

}

For C class in package2, the code A obj = new A(); throws an error but it's not the case for C class in package1. That's correct because constructor is declared as protected and C in package2 is not a subclass of A, while C is in package1. To that point, I understand.

Where I have a problem is with the code A obj = new A(); in class A2 : wherever it is written, it throws an error The constructor A() is not visible... As class A constructor is declared as protected, why couldn't I instantiate an object of type A in A2 class ?

When I declare A constructor as public, it works fine. Besides, if I put A2 class in package1 by letting code as it is, it works too. It seems that instantiating A object in a subclass of A is only possible if the subclass is located in the same package if A constructor is declared as protected.

However, as you can see, if I first instantiate a A2 object and then call the class A protected aff() method, there it works and the protected rule is respected.

Does someone have the explanation for this error ? When instantiating an object of superclass in its subclass, does this subclass always be located in the same package as its superclass, if superclass constructor is declared as protected ? And why is it the case if so ?

Or does this has to deal with the fact that a constructor is not inherited by subclasses ? But I can't figure out to see why if it's the case...

Thanks a lot in advance for taking time to read and answer :-]

回答1:

This is fun so let me try to summarize it. see JLS#6.6.1

protected can qualify a constructor or a member of a class.

"member" includes field/method (static/instance), nested class/interface (static/inner)

class A {
    protected int f
    protected void m(){}
    protected class X{}
    protected interface Y{}

First, to access a protected constructor/member, the enclosing class (e.g. A) must be accessible. Assume that's the case, then --

--Inside the package --

A protected constructor or member is accessible anywhere within the same package.

--Outside the package --

A protected constructor is only accessible within subclass constructors, either as a super() call, or as an anonymous class instantiation.

A protected static field/method, nested class/interface is accessible anywhere within subclass bodies.


A protected instance field/method is more complex --

  • protected "m" is defined in a class A
  • obj.m is accessed in class B (outside A's package)
  • obj 's type is C

The access obj.m is granted only if B is subclass of A, and C is subclass of B or C is B.

super.m is always allowed; however, it's unclear how JLS frames the issue. It seems that the access should be treated the same as this.m, therefore access is allowed.



回答2:

See Java Language Specification:

A protected member or constructor of an object may be accessed from outside the package in which it is declared only by code that is responsible for the implementation of that object.

Your class A2 is not responsible for the implementation of A in the new A() call.

Meaning, it is not responsible for the implementation of an instance of A, but it is responsible for the implementation of an instance of A2.