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

У меня есть абстрактный класс relation в пакете database.relation и его подкласс Join в пакете database.operations. relation имеет защищенного члена с именем mStructure.

In Join:

public Join(final Relation relLeft, final Relation relRight) {
        super();
        mRelLeft = relLeft;
        mRelRight = relRight;
        mStructure = new LinkedList<Header>();
        this.copyStructure(mRelLeft.mStructure);

        for (final Header header :mRelRight.mStructure) {
        if (!mStructure.contains(header)) {
            mStructure.add(header);
        }
    }
}

На линиях

this.copyStructure(mRelLeft.mStructure);

и

for (final Header header : mRelRight.mStructure) {

Я получаю следующую ошибку:

Поле Relation.mStructure не отображается

Если я помещу оба класса в один и тот же пакет, это отлично работает. Кто-нибудь может объяснить эту проблему?


person Amir Rachum    schedule 18.06.2010    source источник


Ответы (4)


Это работает, но только вы, дети, пытаетесь получить доступ к этой собственной переменной, а не к переменной другого экземпляра (даже если она принадлежит к тому же дереву наследования).

Посмотрите этот пример кода, чтобы понять его лучше:

//in Parent.java
package parentpackage;
public class Parent {
    protected String parentVariable = "whatever";// define protected variable
}

// in Children.java
package childenpackage;
import parentpackage.Parent;

class Children extends Parent {
    Children(Parent withParent ){
        System.out.println( this.parentVariable );// works well.
        //System.out.print(withParent.parentVariable);// doesn't work
    } 
}

Если мы попытаемся скомпилировать с использованием withParent.parentVariable, мы получим:

Children.java:8: parentVariable has protected access in parentpackage.Parent
    System.out.print(withParent.parentVariable);

Он доступен, но только для своей собственной переменной.

person OscarRyz    schedule 18.06.2010
comment
Будет ли подходящим решением определить защищенный метод доступа? - person Amir Rachum; 18.06.2010
comment
Произойдет то же самое. Более интересно было бы узнать, являются ли Join Relation IS-A, и если да, то почему они должны идти в разных пакетах. Наверное, использование промежуточного объекта для абстрагирования структуры и сгодится. Я бы посоветовал вам пока поместить их в один пакет, просто чтобы избежать паралича программирования. - person OscarRyz; 19.06.2010
comment
Я полагаю, что ваше первое предложение будет более точным, если вы скажете, что внутри дочернего класса вы можете получить доступ к этому члену в любом экземпляре дочернего класса, или в любом экземпляре класса, который наследуется от дочернего класса, но не любой экземпляр класса, от которого наследуется дочерний класс. (См. раздел 6.6.2.1 спецификации: docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6.2). Таким образом, он может видеть это в дальнейших производных членах дерева наследования, но не в менее производных членах. - person Tim Goodman; 20.03.2014
comment
По общему признанию, это своего рода глоток, чтобы сказать. - person Tim Goodman; 20.03.2014
comment
@TimGoodman Я не вижу в 6.6.2.1 ничего, что делало бы это различие. Единственное, что близко, это использование слова «объект», а не «класс» в единственном абзаце под #6.6.2. - person user207421; 08.07.2014
comment
@EJP Раздел 6.6.2.1 касается доступа по полному имени, например. Q.Id, и говорит, что доступ разрешен [внутри S] тогда и только тогда, когда тип выражения Q равен S или подклассу S. Таким образом, очевидно, что один экземпляр может получить доступ к защищенному члену в другом экземпляре, если он имеет правильный тип. - person Tim Goodman; 08.07.2014
comment
@EJP В случае с OP доступ mRelLeft.mStructure терпит неудачу не потому, что он обращается к нему из экземпляра, отличного от mRelLeft, а потому, что тип времени компиляции mRelLeft (Relation) является менее производным, чем класс, из которого он обращается к нему (Join). Если бы mRelLeft имел тип времени компиляции Join или тип времени компиляции, который был более производным, чем Join, доступ был бы успешным. (Но, как сказал бы Левар Бертон, не верьте мне на слово, достаточно просто попробовать и убедиться.) - person Tim Goodman; 08.07.2014
comment
Кажется, это не работает из разных пакетов. Из другого проекта (библиотеки). - person Jacob; 09.01.2015
comment
Это было сложно понять! К нему можно получить доступ из класса, который его расширяет, но не путем создания объекта надкласса ref и попытки его получить. Я нашел это действительно сложным - person Ced; 14.06.2016

Небольшое предостережение относительно защищенного:

6.6.2 Подробная информация о защищенном доступе

Доступ к защищенному члену или конструктору объекта возможен из-за пределов пакета, в котором он объявлен, только кодом, отвечающим за реализацию этого объекта.

person Marcus Adams    schedule 18.06.2010
comment
Я нахожу здесь полезным пример из §6.6.7. - person Artefacto; 18.06.2010
comment
А формальное определение, разъясняющее ответственность за реализацию, находится в §6.6.2.1. - person meriton; 18.06.2010

Если protected, ваш экземпляр Join не может получить доступ к mStructure в других экземплярах (relRight, relLeft) вне пакета.

РЕДАКТИРОВАТЬ:

Таблица здесь достаточно хорошо объясняет эту ситуацию. Я отметил виновника в вашем вопросе []s

Access Levels
Modifier    Class Package Subclass  World
public      Y     Y       Y         Y
protected   Y    [Y]      Y         N
no modifier Y     Y       N         N
private     Y     N       N         N
person Lauri Lehtinen    schedule 18.06.2010
comment
Ммммм, ваше первое объяснение говорит только о том, что ОП спрашивает, в первую очередь, не может получить к нему доступ. Ваше редактирование не совсем проясняет проблему. - person OscarRyz; 18.06.2010
comment
Я думаю, что мое 1-е объяснение говорит почти то же самое, что и ваше. - person Lauri Lehtinen; 18.06.2010
comment
А по поводу редактирования, как таблица не проясняет проблему? OP описал то самое поведение, которое можно было бы ожидать на основе таблицы: экземпляр класса может получить доступ к защищенным членам другого экземпляра любого класса, если они находятся в одном пакете. Кроме того, экземпляр класса может получить доступ к защищенным членам, определенным в его родительском классе, даже если родительский класс находится в другом пакете. - person Lauri Lehtinen; 18.06.2010
comment
В тексте, сопровождающем цитируемую вами таблицу, конкретно говорится, что разрешено выполнение OP. Модификатор protected указывает, что доступ к члену возможен только в пределах его собственного пакета (как в случае с package-private) и, кроме того, подклассом его класса в другом пакете. - person Peter Recore; 18.06.2010
comment
Может быть, я блаженно читаю это неправильно тогда. Я предполагаю, что это сводится к тому, что считается подклассом в этом контексте. - person Lauri Lehtinen; 18.06.2010

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

Вы можете применить несколько решений, например, если возможно, вы можете объявить в родительском классе эти два метода:

protected void copyRelationStructure(Relation r) {
  this.copyStructure(r.mStructure);
}

protected void mergeRelationStructure(Relation r) {
  for (final Header header: r.mStructure) {
    if (!mStructure.contains(header)) {
      mStructure.add(header);
    }
  }
}

А затем в детском коде замените:

this.copyStructure(mRelLeft.mStructure);

for (final Header header :mRelRight.mStructure) {
  if (!mStructure.contains(header)) {
    mStructure.add(header);
  }
}

С:

this.copyRelationStructure(mRelLeft);
this.mergeRelationStructure(mRelRight);

Это должно сработать. Теперь Relation несет ответственность за предоставление методов, позволяющих выполнять операции с внутренними элементами для своих дочерних элементов. Вероятно, причина этой политики заключается в том, что дети не должны связываться с внутренними компонентами родителей, если только они не являются частью одного и того же пакета программного обеспечения, чтобы ограничить несовместимости.

person user1039663    schedule 31.07.2017