Защищенный конструктор и доступность - PullRequest
29 голосов
/ 01 марта 2011

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

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

Ответы [ 4 ]

18 голосов
/ 01 марта 2011

Согласно спецификации Java (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 является выражением Primary , тогда доступ разрешен.

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

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

9 голосов
/ 01 марта 2011

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 здесь: он не может получить доступ защищенные члены х и у его параметр р, потому что пока Point3d (класс, в котором ссылки на поля х и у встречаются) является подклассом Точка (класс, в котором х и у заявлено), не участвует в реализация точки (тип параметр р). Метод delta3d может получить доступ к защищенным членам его параметр q, потому что класс Point3d является подклассом Point и является участвует в реализации Point3d. Метод дельта может попытаться приведите (§5.5, §15.16) свой параметр к быть Point3d, но этот актерский состав будет сбой, вызывая исключение, если класс р во время выполнения не было Point3d.

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

4 голосов
/ 01 февраля 2013

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

public void test() {
    A obj = new A(){}; // no compilation error; why? you use anonymous class 'override'
    ...
3 голосов
/ 01 марта 2011

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

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

Чтобы получить объект класса 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.
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...