Почему я не могу использовать защищенные конструкторы вне пакета?

Почему я не могу использовать защищенные конструкторы вне пакета для этого фрагмента кода:

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

Check.java

package test;
public class Check extends Example {
  void m1() {
     Example ex=new Example(); //compilation error
  }
}
  • Почему я получаю ошибку, хотя я расширил класс? Пожалуйста, объясните

EDIT:

Ошибка компиляции:

The constructor Example() is not visible

Ответы

Ответ 1

Защищенный модификатор

используется только в пакете и в подклассах вне пакета. Когда вы создаете объект с помощью Example ex=new Example();, он по умолчанию вызовет конструктор родительского класса.

В качестве защищенного конструктора родительского класса вы получаете ошибку времени компиляции. Вы должны вызвать защищенный конструктор в соответствии с JSL 6.6.2.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(); // Compile time error saying SuperConstructorCall() has protected access in SuperConstructorCall
    }
}

Пример 2, соответствующий 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 
    }
}

Ответ 2

Обычно protected означает только доступ к подклассам или классам в одном пакете. Однако вот правила для конструкторов из JLS:

6.6.2.2. Квалифицированный доступ к защищенному конструктору

Пусть C - класс, в котором объявлен защищенный конструктор, и пусть S - самый внутренний класс, в заявлении которого используется защищенный конструктор. Тогда:

Если доступ осуществляется вызовом конструктора суперкласса super (...), или квалифицированный вызов конструктора суперкласса E.super(...), где E является Первичным выражением, тогда доступ разрешен.

Если доступ осуществляется с помощью выражения создания экземпляра анонимного класса новый C (...) {...}, или создание квалифицированного экземпляра анонимного класса выражение E.new C (...) {...}, где E - первичное выражение, тогда доступ разрешен.

Если доступ осуществляется с помощью простого экземпляра создания экземпляра класса new C (...) или выражение для создания экземпляра квалифицированного класса E.new C (...), где E - первичное выражение или ссылка на метод выражение C:: new, где C - тип ClassType, тогда доступ не является разрешенный. К защищенному конструктору можно получить доступ к экземпляру класса (которое не объявляет анонимный класс) или ссылочное выражение метода только из пакета, в котором оно определяется.

В качестве примера это не компилируется

public class Example extends Exception {

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

но это делает

public class Example extends Exception {

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

и это делает

public class Example {

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

Итак, правила понятны, но я не могу сказать, что понимаю причины, лежащие в их основе!

Ответ 3

Фактически вы уже используете защищенный конструктор примера, потому что Check имеет неявный конструктор и неявный вызов конструктора примера:

public Check() {
    super();
}