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

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

В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 не видно

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

Ответы на вопрос(4)

защищенный:

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

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

 meriton18 июн. 2010 г., 20:00
А формальное определение, поясняющее «ответственного за реализацию», содержится в §6.6.2.1.
 Artefacto18 июн. 2010 г., 19:55
Я нахожу пример под §6.6.7 полезным здесь.

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
 Peter Recore18 июн. 2010 г., 19:54
В тексте, сопровождающем таблицу, которую вы цитируете, конкретно сказано, что разрешено выполнение OP - «Защищенный модификатор указывает, что доступ к члену возможен только в его собственном пакете (как с package-private) и, кроме того, подклассом его класс в другой упаковке. "
 Lauri Lehtinen18 июн. 2010 г., 20:10
Может быть, я блаженно читаю это неправильно тогда. Я предполагаю, что все сводится к тому, что в данном контексте считается «подклассом».
 Lauri Lehtinen18 июн. 2010 г., 19:46
Я думаю, что мое первое объяснение говорит почти то же самое, что и ваше.
 OscarRyz18 июн. 2010 г., 19:43
Mmmhh ваше первое объяснение только говорит, OP спрашивают, в первом месте,"не могу получить к нему доступ", Ваше редактирование не совсем проясняет проблему.
 Lauri Lehtinen18 июн. 2010 г., 19:51
А что касается редактирования, как таблица не проясняет проблему? ОП описал само поведение, которое можно ожидать на основе таблицы - экземпляр класса может получить доступ к защищенным членам другого экземпляра любого класса, если они находятся в одном и том же пакете. Кроме того, экземпляр класса может обращаться к защищенным членам, определенным в его родительском классе, даже если родительский класс находится в другом пакете.

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

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 несет ответственность за предоставление методов, которые позволяют своим дочерним элементам выполнять операции с самим собой. Вероятно, причина этой политики заключается в том, что дети не должны связываться с внутренними компонентами родителей, если они не являются частью одного и того же пакета программного обеспечения для ограничения несовместимости.

Решение Вопроса

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

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

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

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

 Jacob09 янв. 2015 г., 14:02
Кажется, он не работает из разных пакетов. Из другого проекта (библиотеки).
 Ced14 июн. 2016 г., 10:14
Это было сложно понять! Получить доступ к нему можно из класса, который его расширяет, но не создавая объект ref суперкласса и пытаясь его получить. Я нашел это действительно сложно
 Tim Goodman20 мар. 2014 г., 02:48
По общему признанию, это - глоток, чтобы сказать.
 Tim Goodman08 июл. 2014 г., 18:44
@EJP Раздел 6.6.2.1 адресует доступ по определенному имени, например,Q.Idи говорит "доступ разрешен [в пределахS] тогда и только тогда, когда тип выраженияQ являетсяS или подклассSMsgstr "Очевидно, что один экземпляр может получить доступ к защищенному элементу в другом экземпляре, если он имеет правильный тип.
 Amir Rachum18 июн. 2010 г., 21:58
Будет ли подходящим решением определить защищенный метод доступа?
 OscarRyz18 июн. 2010 г., 22:38
То же самое случилось бы. Более интересно было бы узнать, еслиJoin ЭТОRelation и если да, то почему они должны идти в разных упаковках. Вероятно, используя промежуточный объект, чтобы абстрагировать структуру и будет делать. Я бы посоветовал вам переместить их в один пакет на данный момент, просто чтобы не попасть в паралич кодирования.
 user20742108 июл. 2014 г., 11:45
@TimGoodman Я не вижу в 6.6.2.1 ничего такого, что могло бы сделать это различие. Единственное, что подходит ближе - это использование слова «объект», а не «класс» в одном абзаце под# 6.6.2 сам.
 Tim Goodman08 июл. 2014 г., 18:45
@EJP В случае ОП доступmRelLeft.mStructure терпит неудачу не потому, что он обращается к нему из другого экземпляра, чемmRelLeft, а скорее потому что тип времени компиляцииmRelLeft (Relation) менее производный, чем класс, к которому он обращается (Join). ЕслиmRelLeft имел тип времени компиляцииJoinили тип времени компиляции, который был более производным, чемJoin, доступ будет успешным. (Но, как сказал бы Левар Бертон: «Не верь мне на слово», достаточно просто попробовать и посмотреть.)
 Tim Goodman20 мар. 2014 г., 02:44
Я считаю, что ваше первое предложение будет немного более точным, если вы скажете, что в дочернем классе вы можете получить доступ к этому члену в любом экземпляре дочернего класса,или любой экземпляр класса, который наследуется от дочернего класса, но не любой экземпляр класса, от которого наследуется дочерний класс. (См. Раздел 6.6.2.1 спецификации:docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6.2). Таким образом, он может видеть это в дериватизированных элементах дерева наследования, но не в менее производных.

Ваш ответ на вопрос