Предположим, что у меня есть общий class Generic<A extends BaseType>
.
Есть ли заметная разница в отношении спецификации языка Java между двумя объявлениями типа?
Generic<?>
Generic<? extends BaseType>
Как насчет вложенных подстановочных знаков?
List<Generic<?>>
List<Generic<? extends BaseType>>
Размышляя об этом, я бы предположил, что это эквивалентно. Generic
указывает, что параметр типа A
имеет BaseType
для верхней границы.
Таким образом, подстановочный знак всегда должен быть "автоматически" или "неявно" ограничен BaseType
, независимо от того, я конкретно его укажу или нет.
Ниже я пытаюсь примирить свою интуицию с JLS.
Мне не удалось найти информацию о "неявных" границах, поэтому я начал с рассмотрения правил подтипирования.
Считывая раздел JLS о подтипирование $4.10.2, он говорит:
Учитывая объявление универсального типа
C<F1,...,Fn>
(n > 0), прямые супертипы параметризованного типаC<T1,...,Tn>
, , где Ti (1 ≤ я ≤ n) являются типом, все из следующего:
D<U1 θ,...,Uk θ>
, гдеD<U1,...,Uk>
- общий тип, являющийся прямым супертипом типового типаC<T1,...,Tn>
, а θ - подстановка [F1: = T1,..., Fn: = Tn].
C<S1,...,Sn>
, где Si содержит Ti (1 ≤ я ≤ n) (п. 4.5.1).
(акцент мой)
Из того, что я понимаю, "подстановочные знаки" не считаются "типами" в JLS. Таким образом, это не может применяться к первым двум, но оно применимо к двум примерам List
.
Вместо этого это должно применяться:
Учитывая объявление универсального типа
C<F1,...,Fn>
(n > 0), прямые супертипы параметризованного типаC<R1,...,Rn>
, где хотя бы один из Ri (1 ≤ я ≤ n) является аргументом типа подстановочного символа, являются прямыми супертипами параметризованного типаC<X1,...,Xn>
, который является результатом применения преобразования захвата вC<R1,...,Rn>
(§5.1.10).
(акцент мой)
Применение конверсия захвата $5.1.10 в Generic<?>
и Generic<? extends BaseType>
; Я думаю, что я получаю те же границы по новым переменным типа. После преобразования захвата я могу использовать правила "содержит", чтобы установить подтипирование.
В первом примере через
Если Ti является аргументом типа подстановочного типа (п. 4.5.1) формы?, то Si - переменная нового типа, верхняя граница которой Ui [A1: = S1,..., An: = Sn] и чьи нижняя граница - нулевой тип (§4.1).
Так как A 1 is BaseType
, свежая переменная имеет верхнюю границу BaseType
.
Во втором случае через
Если Ti является аргументом типа подстановочной формы формы? расширяет Bi, то Si является переменной нового типа, верхняя граница которой равна glb (Bi, Ui [A1: = S1,..., An: = Sn]), нижняя граница которой является нулевым типом.
glb (V1,..., Vm) определяется как V1 и... и Vm.
Я получаю glb(BaseType, BaseType)
, что опять же BaseType
.
Итак, похоже, что отношение подтипирования между Generic<?>
и Generic<? extends BaseType>
идет в обоих направлениях в соответствии с JLS, которое соответствует моей интуиции.
Для вложенных подстановочных знаков я бы использовал правило "содержит" :
Утверждается, что аргумент типа T1 содержит другой аргумент типа T2, записанный T2 <= T1, если набор типов, обозначаемый T2, является предположительно a подмножество множества типов, обозначаемое T1 под рефлексивным и переходное замыкание следующих правил (где <: обозначает подтипирование (§4.10)):
? extends T <= ? extends S if T <: S
? extends T <= ?
? super T <= ? super S if S <: T
? super T <= ?
? super T <= ? extends Object
T <= T
T <= ? extends T
T <= ? super T
В сочетании с
C<S1,...,Sn>, where Si contains Ti (1 ≤ i ≤ n) (§4.5.1).
сверху, я получаю:
List<Generic<?>>
является прямым супертипом List<Generic<? extends BaseType>>
, если Generic<?>
содержит Generic<? extends BaseType>>
Хотя, я не вижу, как я использую правило contains. Единственной дополнительной информацией, которую я могу использовать, является подтипирование в соответствии с правилами. Я уже знаю, что подтипирование происходит в обоих направлениях между двумя типами.
Хотя, если содержит ответ с подтипированием между ними, я мог бы также показать, что List<String>
является подтипом List<Object>
, которого он не является и не должен быть.
Далее, мне нужно показать что-то из формы Type <= OtherType
, и единственным правилом с правой частью формы "type" является T <= T
, поэтому эти правила, похоже, вообще не помогают.
Как мне получить, что List<Generic<?>>
и List<Generic<? extends BaseType>>
являются подтипами друг друга через JLS?