Защищенный конструктор и доступность

Почему мы не можем создать экземпляр classа с защищенным конструктором, если его дочерний элемент находится в другом пакете? Если доступ к защищенным переменным и методам возможен, почему же не применяется такое же правило для защищенного конструктора?

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(); } } 

В соответствии с Java Spec ( https://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.6.2.2 )

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

Пусть C – class, в котором объявлен protected конструктор, и пусть S – самый внутренний class, в объявлении которого используется использование protected конструктора. Затем:

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

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

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

В вашем случае доступ к защищенному конструктору A из B будет легальным из конструктора B посредством вызова super() . Однако доступ с использованием new не является законным.

JLS 6.6.7 отвечает на ваш вопрос. Подclass получает доступ только к защищенным членам его родительского classа, если он предполагает реализацию его родителя. Поэтому вы не можете создать экземпляр родительского объекта в дочернем classе, если родительский конструктор защищен и находится в другом пакете …

6.6.7 Пример: защищенные поля, методы и конструкторы Рассмотрим этот пример, в котором объявляется пакет точек:

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

и пакет threePoint объявляет:

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

который определяет class Point3d. В методе delta возникает ошибка времени компиляции: он не может получить доступ к защищенным членам x и y своего параметра p, поскольку в то время как Point3d (class, в котором встречаются ссылки на поля x и y), является подclassом Point ( class, в котором объявлены x и y), он не участвует в реализации Точки (тип параметра p). Метод delta3d может получить доступ к защищенным членам его параметра q, поскольку class Point3d является подclassом Point и участвует в реализации Point3d. Метод delta мог бы попытаться использовать (5.35, §15.16) его параметр как Point3d, но этот приведение не получило бы результата, вызывая исключение, если class p во время выполнения не был Point3d.

В методе warp также возникает ошибка времени компиляции: он не может получить доступ к защищенному члену z своего параметра a, потому что, пока class Point (class, в котором происходит ссылка на поле z), участвует в реализации Point3d ( тип параметра a), он не является подclassом Point3d (class, в котором z объявлен).

Я согласен с предыдущими плакатами, не знаю, почему вы хотели бы это сделать (создайте родителя таким образом в расширении classа), но вы можете даже сделать что-то вроде этого:

 public void test() { A obj = new A(){}; // no compilation error; why? you use anonymous class 'override' ... 

Зачем вам нужен A obj=new A(); в classе, тогда как объект classа b сам по себе является объектом class A

И в classе c он дает ошибку, потому что вы получаете доступ к защищенному свойству classа A, который является конструктором.

Чтобы получить объект classа А в этом случае, вы должны использовать эту функцию в classе А

 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. } 

это работает так же, как и защищенные поля.

  • Конструктор Java не компилируется должным образом
  • DataContractSerializer не вызывает мой конструктор?
  • Как получить имена параметров конструкторов объекта (reflection)?
  • Деструкторы встроенных типов (int, char и т. Д.)
  • Перегрузка конструктора в Java - лучшая практика
  • Делает много в конструкторах плохо?
  • Сеттерные методы или конструкторы
  • Кто удаляет память, выделенную во время «новой» операции, которая имеет исключение в конструкторе?
  • Как я могу назвать один конструктор из другого в Java?
  • вызов чистой виртуальной функции из конструктора базового classа
  • Вызов базового конструктора в C #
  • Давайте будем гением компьютера.