Подтвердить что ты не робот

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

Теперь 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:

Поле Area < capture # 1-of? > . 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 привело к тому, что поля, параметризованные по типу, стали невидимыми?

4b9b3361

Ответ 1

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

Обходной путь заключается в использовании:

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

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

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

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


В интересах исследования давайте сделаем полный анализ вашего примера на основе 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. Класс наследует от своего прямого суперкласса и прямых суперинтерфейсов все типы неединичных членов суперкласса и суперинтерфейсов, которые оба доступны для кода в классе, а не скрыты объявлением в классе.