Ошибка компиляции на наследовании универсального внутреннего класса, расширяющегося с границами

У меня есть проблема при компиляции универсального класса с внутренним классом. Класс расширяет универсальный класс, внутренний класс также.

Здесь интерфейс реализовал:

public interface IndexIterator<Element>
    extends Iterator<Element>
{
  ...
}

Универсальный суперкласс:

public abstract class CompoundCollection<Element, Part extends Collection<Element>>
    implements Collection<Element>
{
  ...

  protected class CompoundIterator<Iter extends Iterator<Element>>
      implements Iterator<Element>
  {
    ...
  }
}

Универсальный подкласс с ошибкой компилятора:

public class CompoundList<Element>
    extends CompoundCollection<Element, List<Element>>
    implements List<Element>
{
  ...

  private class CompoundIndexIterator
      extends CompoundIterator<IndexIterator<Element>>
      implements IndexIterator<Element>
  {
    ...
  }
}

Ошибка:

type parameter diergo.collect.IndexIterator<Element> is not within its bound
       extends CompoundIterator<IndexIterator<Element>>
                                             ^

Что не так? Код компилирует с затмением, но не с компилятором java 5 (я использую муравья с java 5 на Mac и затмеваю 3.5). Нет, я не могу преобразовать его в статический внутренний класс.

9
задан Alexander Pogrebnyak 9 April 2010 в 21:38
поделиться

2 ответа

Спецификация языка Java, §8.1.3 , определяет семантику подкласса внутренних типов следующим образом:

Кроме того, для каждого суперкласса S из C, который сам является прямым внутренний класс класса SO, существует экземпляр SO, связанный с i, известный как , непосредственно включающий экземпляр i по отношению к S. Непосредственно включающий экземпляр объекта с относительно прямого суперкласса своего класса, если таковой имеется, определяется, когда вызывается конструктор суперкласса {{1 }} через явный оператор вызова конструктора .

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

class Base<E> {
    E e;

    protected class BaseInner<I extends E>{
        E e() { return e; }
    } 
} 

class StrangeSub extends Base<Integer> {
    protected class StrangeSubInner extends Base<String>.BaseInner<String> {}
}

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

    StrangeSub ss = new StrangeSub();
    ss.e = 42;
    String s = ss.new StrangeSubInner().e();

Компилятор eclipse принимает спецификацию языка Java как номинал и принимает приведенный выше код, даже не выдавая предупреждения о «непроверенном». Хотя это, возможно, технически соответствует JLS, это явно нарушает его намерения.

Компилятор Sun Java отклоняет объявление StrangeSubInner с:

Test.java:32: type parameter java.lang.String is not within its bound
        protected class StrangeSubInner extends Base<String>.BaseInner<String> {}
                                                                       ^

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

class StrangeSub extends Base<Integer> {
    protected class StrangeSubInner extends BaseInner<Integer> {}
}

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

Чтобы обойти это ограничение, я сначала попытался бы избавиться от параметра типа CompoundIterator .

8
ответ дан 4 December 2019 в 21:49
поделиться

Возможно, это небольшой прогресс, но мне удалось сократить приведенный выше код до следующего кода, который по-прежнему демонстрирует такое же странное поведение:

class Base<E> { 
    protected class BaseInner<I extends E>{
    } 
} 

class Sub<E> extends Base<E>{ 
    class SubInner extends BaseInner<E> { 
    }
} 
1
ответ дан 4 December 2019 в 21:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: