Изменения в доступе переменных для общих классов в Java 7 - программирование
Подтвердить что ты не робот

Изменения в доступе переменных для общих классов в Java 7

Вот простой пример некоторого кода, который компилируется с использованием Java 6, но не компилируется в Java 7.

public class Test<T extends Test> {

  private final int _myVar;

  public Test(int myVar) {
    _myVar = myVar;
  }

  public int get(TestContainer<T> container){
    T t = container.get();
    return t._myVar;
  }

  private static class TestContainer<T extends Test> {
    private final T _test;
    private TestContainer(T test) {
      _test = test;
    }
    public T get(){
      return _test;
    }
  }
}

В Java 7 он не скомпилируется в методе get(TestContainer<T> container) с ошибкой:

ошибка: _myVar имеет закрытый доступ в тесте

Я не понимаю, почему это больше не компилируется - по моему мнению, это нужно. Переменная t имеет тип t, который должен расширять Test. Он пытается получить доступ к полю _myVar экземпляра Test из класса Test.

В самом деле, если я изменил метод get(TestContainer<T> container) на следующий, он компилирует (без предупреждений):

public int get(TestContainer<T> container){
  Test t = container.get();
  return t._myVar;
}
  • Почему это больше не компилируется?
  • Было ли это ошибкой в ​​Java 6? Если да, то почему?
  • Является ли это ошибкой в ​​Java 7?

У меня был Google и искал в базе данных Oracle, но ничего не нашел на этом...

4b9b3361

Ответ 1

§4.9... Тогда тип пересечения имеет те же элементы, что и тип класса (§8), с пустым телом, прямым суперклассом Ck и прямые суперинтерфейсы T1 ',..., Tn', объявленные в том же пакете, в котором появляется тип пересечения.

Из моего понимания этой части JLS ваш случай с переменной типа <T extends Test> создает следующее пересечение:

package <the same as of Test>;

class I extends Test {}

Поэтому, когда вы обращаетесь к членам типа T, вы фактически получаете доступ к членам типа пересечения I. Поскольку частные члены никогда не наследуются подтипами доступа к такому члену с ошибкой компиляции. С другой стороны, доступ к конфиденциальным пакетам (по умолчанию) и защищенным членам допускается тем фактом, что пересечение

... объявлен в том же пакете, в котором появляется тип пересечения.

Ответ 2

См. комментарий @pingw33n для ответа, но способ исправить это - удалить общие параметры для вложенного класса. Если у вас нет варианта использования, где внутренний и внешний Т могут быть разными, они являются избыточными. Все, что они делают, вызывает это горе.

Ответ 3

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

public int get(TestContainer<T> container){
  T t = container.get();
  return ((Test) t)._myVar;
}