Подтвердить что ты не робот

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

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

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

Ответ 1

В соответствии с 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 - класс, в котором объявлен конструктор protected, и пусть S является самым внутренним классом, в объявлении которого используется конструктор protected. Тогда:

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

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

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

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

Ответ 2

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

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

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

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

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

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

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

Ответ 3

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

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

Чтобы получить объект класса А в этом случае, вы должны использовать эту функцию в классе 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.
}

Ответ 4

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

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

Ответ 5

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