Изменения в доступе переменных для общих классов в 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, но ничего не нашел на этом...
Ответы
Ответ 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;
}