41

Why can't I use protected constructors outside the package for this piece of code:

package code;
public class Example{
    protected Example(){}
    ...
}

Check.java

package test;
public class Check extends Example {
  void m1() {
     Example ex=new Example(); //compilation error
  }
}
  1. Why do i get the error even though i have extended the class? Please explain

EDIT:

Compilation error:

The constructor Example() is not visible

Cœur
  • 37,241
  • 25
  • 195
  • 267
Abhilash28
  • 645
  • 1
  • 9
  • 15
  • Knowing the compilation error could be quite useful in diagnosing the problem... – Jonny Henly Apr 09 '15 at 05:11
  • Look at this http://stackoverflow.com/questions/5150748/protected-constructor-and-accessibility you can use a protected constructor of a superclass in the constructor of a subclass but not to instantiate a superclass instance Anywhere else. – redge Apr 09 '15 at 05:17
  • More or less the same reason you can't do `public class Example {protected int i;} /* in another package: */ public class Check extends Example {void m1(Example ex) {ex.i = 2;}}` – user253751 Apr 09 '15 at 07:44
  • The choice of duplicate question is unfortunate, since these two questions, while related, are distinct, and the other question doesn’t answer this one at all. – Konrad Rudolph Jan 08 '20 at 14:19

3 Answers3

14

Usually protected means only accessible to subclasses or classes in the same package. However here are the rules for constructors from the JLS:

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.

As an example, this does not compile

public class Example extends Exception {

    void method() {
        Exception e = new Exception("Hello", null, false, false);
    }
}

but this does

public class Example extends Exception {

    Example() {
        super("Hello", null, false, false);
    }
}

and so does this

public class Example {

    void method() {
        Exception e = new Exception("Hello", null, false, false) {};
    }
}

So the rules are clear, but I can't say I understand the reasons behind them!

Paul Boddington
  • 37,127
  • 10
  • 65
  • 116
6

protected modifier is used only with in the package and in sub-classes outside the package. When you create a object using Example ex=new Example(); it will call parent class constructor by default.

As parent class constructor being protected you are getting a compile time error. You need to call the protected constructor according to JSL 6.6.2.2 as shown below in example 2.

package Super;

public class SuperConstructorCall {

    protected SuperConstructorCall() {
    }

}

package Child;

import Super.SuperConstructorCall;

public class ChildCall extends SuperConstructorCall
{

    public static void main(String[] args) {

        SuperConstructorCall s = new SuperConstructorCall(); // Compile time error saying SuperConstructorCall() has protected access in SuperConstructorCall
    }
}

Example 2 conforming to JLS 6.6.2.2:

package Super;

    public class SuperConstructorCall {

    protected SuperConstructorCall() {
    }

}

package Child;

import Super.SuperConstructorCall;

public class ChildCall extends SuperConstructorCall
{

    public static void main(String[] args) {

        SuperConstructorCall s = new SuperConstructorCall(){}; // This will work as the access is by an anonymous class instance creation expression 
    }
}
kittu
  • 6,662
  • 21
  • 91
  • 185
  • 1
    No. `protected` can be used across packages. You just have to extend the class. `default` scope is *within a package*. **The protected modifier specifies that the member can only be accessed within its own package (as with package-private) and, in addition, by a subclass of its class in another package.** – TheLostMind Apr 09 '15 at 05:28
  • 3
    Still the answer is not convincing, I understand that it will call the parent class consturtor ie> Example() which is protected but as we know we can use protected modifers outside the package if we extend that class then why that doesn't work here in case of constructors? – Abhilash28 Apr 09 '15 at 05:31
  • 1
    Why would you need to call the constructor of a superclass independently? You have access to methods of superclass directly if they are not default access or private. – Ya Wang Apr 09 '15 at 05:36
3

In fact you are already using protected constructor of Example because Check has an implicit constructor and implicit Example constructor call:

public Check() {
    super();
}
Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275