С параметризованными типами в Java, как правила, проверяющие, находится ли параметр в пределах его привязки, работают точно для подстановочных знаков ?
Дан такой класс:
class Foo {}
Экспериментируя с тем, что принимает компилятор, узнает, что:
? extends
подстановочный знак разрешен с использованием несвязанного типа интерфейса: Foo extends Runnable>
действительно ? extends
подстановочный знак с использованием несвязанного типа класса не допускается: Foo extends Thread>
недопустим. В этом есть смысл, потому что ни один тип не может быть подтипом одновременно Number
и Thread
? super
подстановочный знак, нижняя граница подстановочного знака должна быть подтипом границы переменной типа: Foo super Runnable>
не допускается, потому что Runnable
не является подтипом Number
. Опять же, это ограничение имеет смысл. Но где эти правила определены? Глядя на раздел 4.5 спецификации языка Java, я не вижу ничего, что отличает интерфейсы от классов; и при применении моей интерпретации JLS Foo super Runnable>
считается допустимым. Так что я, наверное, что-то неправильно понял. Вот моя попытка:
Из этого раздела JLS:
Параметризованный тип состоит из имени класса или интерфейса C и фактического списка аргументов типа
. Ошибка времени компиляции, если C не является именем универсального класса или интерфейса или если количество аргументов типа в фактическом списке аргументов типа отличается от количества объявленных параметров типа C. В дальнейшем, когда мы говорим типа класса или интерфейса, мы также включаем универсальную версию, если она явно не исключена. В этом разделе пусть A1, ..., An будут параметрами формального типа C, и пусть be Bi будет объявленной границей Ai. Обозначение [Ai: = Ti] обозначает замену переменной типа Ai на тип Ti для 1 Пусть P = G
быть параметризованным типом. Это должно быть так, что после того, как P подвергается преобразованию захвата (§5.1.10), приводящему к типу G , для каждого фактического аргумента типа Xi, 1
Примените это к P = Foo super Runnable>
: что дает C = Foo
, n = 1, T1 = ?super Runnable
и B1 = Число
.
Для преобразования захвата применяется эта часть определения преобразования захвата :
Если Ti является аргументом типа подстановочного знака для форма? super Bi, тогда Si - переменная нового типа, верхняя граница которой равна Ui [A1: = S1, ..., An: = Sn], а нижняя граница - Bi.
Это дает G Foo
где X
- это переменная нового типа с верхней границей Number
и нижней границей Runnable
. Я не вижу ничего явно запрещающего такую переменную типа.
В B1 = Number
нет переменных типа, поэтому Bi [A1: = X1, ..., An: = Xn] равно по-прежнему просто Число
.
X
имеет число
как верхнюю границу (исходя из преобразования захвата) и согласно правилам подтипов «Прямые супертипы переменной типа - это перечисленные типы in its bound », поэтому X
<:> Number (= Bi [A1: = X1, ..., An: = Xn]), поэтому этот параметр находится в пределах его границ. (Но это не так!)
Следуя тем же рассуждениям , каждый подстановочный знак находится в пределах своих границ, поэтому здесь что-то не так ... Но где именно это рассуждение пошло не так? Как эти правила работают при правильном применении?