3

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 :-]

  • Your question could have been made a whole lot smaller. See [Minimal, Complete, and Verifiable](http://stackoverflow.com/help/mcve). – Andreas Aug 28 '15 at 01:22
  • 1
    `protected` is fun:) it appears that a protected constructor can only be invoked from subclass constructors. – ZhongYu Aug 28 '15 at 04:04
  • How is this lack of specification reading become a good question. – itwasntme Aug 28 '15 at 08:52
  • I apologize for the length of my question, I wanted to be as clear as possible for everyone. Next time I'll try to properly match Minimal, Complete, and Verifiable requirements :-] @itwasntme : In fact I found some explanation in Java's specifications but it was horrible to understand... It uses too generic and complex samples for my skills, and too complex english technical speech. I was confused and didn't understand what they wanted to say, and so is the reason why I posted my question here. Reading the specification doesn't always mean that you clearly understand it. – NatsuDragon Aug 28 '15 at 17:02

2 Answers2

3

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.

Andreas
  • 154,647
  • 11
  • 152
  • 247
  • Thank you for your really quick response ! I think I have understood why it works if A2 is in the same package and why it doesn't works if A2 is outside A's package. In this case in fact, only A2's constructor can access to A's constructor through super() or implicit call. – NatsuDragon Aug 28 '15 at 16:38
3

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.

ZhongYu
  • 19,446
  • 5
  • 33
  • 61
  • Thank you for your detailed response ! So, If I understood right, the reason why it works when I put A2 in the same package than A and try to instantiate an A object in A2's body is that in reality A2 is first considered, as an access rights point of view, as a class of the same package as A --before-- being it's subclass ? – NatsuDragon Aug 28 '15 at 16:34
  • @NatsuDragon `protected` implies all the same rights as "package private" (when no keyword is given), so putting `A2` in the same package as `A` allows access because of the *package private* rules of access. The additional rights granted by `protected` don't come into play. – Andreas Aug 28 '15 at 16:46
  • @Andreas I think it is clear for me now. Therefore, additional rights granted by `protected ` only concern subclasses in an outer package. There, `protected ` superclass constructor can only be called by the subclass constructor. Concerning `protected ` instance members of superclass, they have to be accessed through an instance of the subclass (or of its own subclass), where `protected ` static members can be accessed wherever in the subclass. Thanks for the clarification :-] – NatsuDragon Aug 28 '15 at 23:17
  • 1
    @NatsuDragon Correct. Note that the access is granted, even when not accessing own instance (`this`). Often seen in `equals(obj)` methods, where `this.a == ((A2)obj).a` is allowed from code in `A2`. – Andreas Aug 28 '15 at 23:29