Параметризованное поле типа универсального класса становится невидимым после обновления до Java 7 - PullRequest
43 голосов
/ 11 октября 2011

Сейчас Eclipse Indigo SR1 со встроенной поддержкой Java 7 наконец-то вышел через неделю или две, я перевожу свои игровые проекты с Helios SR2 + JDK 1.6_23 на Indigo SR1+ JDK 1.7.0.После полной перестройки всех проектов не удалось скомпилировать только один класс.Это следующий класс, который прекрасно компилируется и работает на Java 1.6 (и 1.5):

public abstract class Area<A extends Area<?>> implements Comparable<Area<?>> {

    private String name;
    private Area<?> parent;
    private Set<A> areas;

    protected Area(String name, A... areas) {
        this.name = name;
        this.areas = new TreeSet<A>();
        for (A area : areas) {
            area.parent = this;
            this.areas.add(area);
        }
    }

    public Set<A> getAreas() {
        return areas;
    }

    // ...
}

Строка area.parent = this; завершается ошибкой со следующей ошибкой parent:

Площадь поля.parent не виден

После первого подозрения на компилятор Eclipse, я попытался с обычным javac из JDK 1.7.0, но он дает в основном ту же ошибку, тогда как javac из JDK 1.6.0_23 успешно без ошибок.

Изменение видимости на protected или по умолчанию решает проблему.Но почему полностью вне меня.Я заглянул на http://bugs.sun.com,, но не смог найти ничего похожего.

Другой способ исправить ошибку компиляции - заменить все используемые A объявления внутри класса на Area<?> (или полностью удалить его):

public abstract class Area<A extends Area<?>> implements Comparable<Area<?>> {

    private String name;
    private Area<?> parent;
    private Set<Area<?>> areas;

    protected Area(String name, Area<?>... areas) {
        this.name = name;
        this.areas = new TreeSet<Area<?>>();
        for (Area<?> area : areas) {
            area.parent = this;
            this.areas.add(area);
        }
    }

    public Set<Area<?>> getAreas() {
        return areas;
    }

    // ...
}

Но это ломаетцель добытчика.В случае, например, следующего класса:

public class Country extends Area<City> {

    public Country(String name, City... cities) {
        super(name, cities);
    }

}

Я ожидаю, что он вернет Set<City>, а не Set<Area<?>>.

Какое изменение в Java 7 вызвало тепараметризованные поля станут невидимыми?

1 Ответ

31 голосов
/ 11 октября 2011

Это похоже на ошибку javac6, которая исправлена ​​в javac7.

Обходной путь откорректирован:

((Area<?>)area).parent = this;

Что кажется действительно странным - зачем нам нужен апгрейд для доступа к члену в суперклассе?

Основная проблема заключается в том, что частные члены специально исключены из наследования, поэтому A не имеет члена parent. Та же проблема может быть продемонстрирована на необщем примере.

Сообщение об ошибке " parent имеет частный доступ в Зоне " не совсем точно, хотя, вероятно, в большинстве случаев подходит. Однако в этом случае, это вводит в заблуждение, лучшее сообщение было бы " A не наследует приватный член 'parent' из области "


Для интереса, давайте проведем полный анализ вашего примера на основе JLS:

  • §4.4: члены переменной типа X с ограничением T & I1 ... In являются членами типа пересечения (§4.9) T & I1 ... In, появляющегося в точке, где объявлена ​​переменная типа.

  • §4.9: тип пересечения имеет те же члены, что и тип класса (§8) с пустым телом, прямым суперклассом Ck и прямыми суперинтерфейсами IT1 , ..., ITn,, объявленными в том же пакете, в котором тип пересечения появляется.

  • §6.6.1: Если член или конструктор объявлен закрытым, тогда доступ разрешается, если и только если он происходит в теле класса верхнего уровня (§7.6), который включает в себя объявление члена или конструктор.

  • §8.2: Члены класса, которые объявлены закрытыми, не наследуются подклассами этого класса.

  • §8.5: класс наследует от своего прямого суперкласса и прямых суперинтерфейсов все не приватные типы членов суперкласса и суперинтерфейсов, которые оба доступны для кода в классе и не скрыты объявлением в классе.

...