Спецификация языка Java, §8.1.3 , определяет семантику внутренних классов подклассов следующим образом:
Кроме того, для каждого суперкласса S
С, который сам является прямым внутренним классом
класса SO, есть экземпляр
ТАК связано с I, известный как
немедленно включающий экземпляр я
в отношении С. немедленно
включающий экземпляр объекта с
уважение к своему классу "прямой
суперкласс, если таковой имеется, определяется, когда
конструктор суперкласса вызывается
через явный вызов конструктора
заявление.
Обратите внимание, что описываемый экземпляр описывается только как определенный класс , а не конкретный тип . Поскольку все экземпляры универсального типа совместно используют один и тот же класс, следующий код будет допустимым:
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
.