41

Why can't we instantiate a class with a protected constructor if its child is in a different package? If protected variables and methods can be accessed, why doesn't the same rule also apply for a protected constructor?

pack1:

package pack1;

public class A {
    private int a;
    protected int b;
    public int c;

    protected A() {    
        a = 10;
        b = 20;
        c = 30;
    }
}

pack2:

package pack2;

import pack1.A;

class B extends A {
    public void test() {
        A obj = new A(); // gives compilation error; why?
        //System.out.println("print private not possible :" + a);
        System.out.println("print protected possible :" + b);
        System.out.println("print public possible :" + c);
    }
}

class C {
    public static void main(String args[]) {
        A a = new A(); // gives compilation error; why?
        B b = new B();
        b.test();
    }
}
Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214
Chandra Kanth
  • 431
  • 1
  • 4
  • 7
  • 1
    Please make an effort to construct your question clearly, format it properly, and tag it appropriately. You have not done any of these. – Matt Ball Mar 01 '11 at 05:14
  • 1
    its clear.. parent A and child B are in two different packages(pack1 and pack2 respectively).. why compiler errors while creating an object of a class(parent A) whose constructor is protected ? – Chandra Kanth Mar 01 '11 at 05:20
  • I believe that instead of accessing `b` from the actual instance, if this had `obj.b` (assuming obj was created or passed successfully) it would also give a compilation error – user85421 Sep 17 '18 at 08:36

5 Answers5

24

According to the Java Spec (https://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.6.2.2)

6.6.2.2. Qualified Access to a protected Constructor

Let C be the class in which a protected constructor is declared and let S be the innermost class in whose declaration the use of the protected constructor occurs. Then:

  • If the access is by a superclass constructor invocation super(...), or a qualified superclass constructor invocation E.super(...), where E is a Primary expression, then the access is permitted.

  • If the access is by an anonymous class instance creation expression new C(...){...}, or a qualified anonymous class instance creation expression E.new C(...){...}, where E is a Primary expression, then the access is permitted.

  • If the access is by a simple class instance creation expression new C(...), or a qualified class instance creation expression E.new C(...), where E is a Primary expression, or a method reference expression C :: new, where C is a ClassType, then the access is not permitted. A protected constructor can be accessed by a class instance creation expression (that does not declare an anonymous class) or a method reference expression only from within the package in which it is defined.

In your case, access to the protected constructor of A from B would be legal from a constructor of B through an invocation of super(). However, access using new is not legal.

Community
  • 1
  • 1
mazaneicha
  • 8,794
  • 4
  • 33
  • 52
10

JLS 6.6.7 answers your question. A subclass only access a protected members of its parent class, if it involves implementation of its parent. Therefore , you can not instantiate a parent object in a child class, if parent constructor is protected and it is in different package...

6.6.7 Example: protected Fields, Methods, and Constructors Consider this example, where the points package declares:

package points;
public class Point {
    protected int x, y;
    void warp(threePoint.Point3d a) {
        if (a.z > 0)        // compile-time error: cannot access a.z
            a.delta(this);
    }
}

and the threePoint package declares:

package threePoint;
import points.Point;
public class Point3d extends Point {
    protected int z;
    public void delta(Point p) {
        p.x += this.x;      // compile-time error: cannot access p.x
        p.y += this.y;      // compile-time error: cannot access p.y
    }
    public void delta3d(Point3d q) {
        q.x += this.x;
        q.y += this.y;
        q.z += this.z;
    }
}

which defines a class Point3d. A compile-time error occurs in the method delta here: it cannot access the protected members x and y of its parameter p, because while Point3d (the class in which the references to fields x and y occur) is a subclass of Point (the class in which x and y are declared), it is not involved in the implementation of a Point (the type of the parameter p). The method delta3d can access the protected members of its parameter q, because the class Point3d is a subclass of Point and is involved in the implementation of a Point3d. The method delta could try to cast (§5.5, §15.16) its parameter to be a Point3d, but this cast would fail, causing an exception, if the class of p at run time were not Point3d.

A compile-time error also occurs in the method warp: it cannot access the protected member z of its parameter a, because while the class Point (the class in which the reference to field z occurs) is involved in the implementation of a Point3d (the type of the parameter a), it is not a subclass of Point3d (the class in which z is declared).

Gursel Koca
  • 20,940
  • 2
  • 24
  • 34
  • constructor is also a member of class, isn't it? – Meet Dec 25 '13 at 07:07
  • Actually, no it isn't. A constructor is NOT a member. And these are not the rules that apply in this case. The real applicable rules are in JLS 6.6.2.2 - see @mazaneicha's answer. – Stephen C May 29 '15 at 23:45
5

I agree with previous posters, don't know why you would want to do this (instantiate parent in that way in extending class) but you could even do something like this:

public void test() {
    A obj = new A(){}; // no compilation error; why? you use anonymous class 'override'
    ...
embuc
  • 465
  • 5
  • 5
  • 3
    just be aware that obj is not a (direct) instance of class `A`, it is an instance of an anonymous subclass of `A` – user85421 Sep 17 '18 at 08:33
3

Why do you need A obj=new A(); in class, whereas object of class b is itself an object of class A

And in class c it is giving error because, you are accessing the protected property of class A which is constructor.

To get object of class A in this case you must use this function in class A

static A getInstance()
{
   A obj = new A(); // create obj of type A.
   return obj; // returns that object by this method. No need to use 'New' kind of instantiation.
}
Community
  • 1
  • 1
Gaurav
  • 28,447
  • 8
  • 50
  • 80
  • constructor of class A is protected. So you can not create object of class A, anywhere else except in class A. So add a static function in class, which will give object of class A. – Gaurav Mar 01 '11 at 05:29
  • FYI , we can create an object of class A anywhere in the same package!! and what do you mean by 1.object of class b is itself an object of class A and 2.in class c it is giving error because, you are accessing the protected property of class A which is constructor .. you only wrote this..!!! – Chandra Kanth Mar 01 '11 at 05:32
  • Protected properties are not accessible out of class itself and child classes. But you are creating object of class A in class C. And class is not related to class A. Whenever you create a object of class it calls constructor of that class. I don't know too much about JAVa, but know OOP. – Gaurav Mar 01 '11 at 05:42
  • for a decorator and to prevent direct instanciation for instance. – Snicolas Sep 22 '11 at 11:48
1

If protected variables and methods can be accessed, why doesn't the same rule also apply for a protected constructor?

Protected variables and methods can only be accessed if the child class in another package extends the class containing the protected variables and methods. You are able to access variable 'b' in child class B because you have extended the class A. You will not be able to access variable 'b' in class C as it is not extending class A.

The only way to access protected constructor in child class is by using parent class reference variable and child class object.

package pack2;

import pack1.A;

class B extends A {
    public void test() {
        A obj = new B(); // will execute protected constructor
        System.out.println("print protected possible :" + b);
    }
}