Можете ли вы указать общий тип, который подклассифицирует другой общий тип _and_ конкретный интерфейс?
У меня есть семейство моделей доменов, каждый из которых имеет подкласс, который расширяет его и реализует определенный интерфейс, например (Cloneable
не является интерфейсом, о котором идет речь, например, для целей):
class A{}
class B extends A implements Cloneable{}
class C{}
class D extends C implements Cloneable{}
Я хочу создать подпись общего типа, которая обеспечит это сопряжение, я пробовал это, FAILS:
<T1,T2 extends T1 & Cloneable> void f ( T1 t1, T2 t2 ){}
но я получаю сообщение в своей IntelliJ IDE "Type parameter cannot be followed by other bounds"
; он все еще FAILS, если я переключу порядок вокруг на:
<T1,T2 extends Cloneable & T1> void f ( T1 t1, T2 t2 ){}
Получаю сообщение "Interface expected here."
Смутно, обе эти подписи WORK:
<T extends A & Cloneable> void f( A a, T t ){}
<T1,T2 extends T1> void f ( T1 t1, T2 t2 ){}
Является ли это просто странным ограничением системы Java generic типа, в которой я не могу иметь общий класс (т.е. T2
), распространять как другой общий класс (т.е. T1
), так и конкретный интерфейс (например, Cloneable
)?
tl; dr: Итак, почему не будет <T1,T2 extends Cloneable & T1> void f ( T1 t1, T2 t2 ){}
компилировать: это ограничение синтаксиса Java generic или я использую неправильный синтаксис?
Ответы
Ответ 1
Ответ находится в JLS 4.4:
TypeParameter:
TypeVariable TypeBoundopt
TypeBound:
extends TypeVariable
extends ClassOrInterfaceType AdditionalBoundListopt
AdditionalBoundList:
AdditionalBound AdditionalBoundList
AdditionalBound
AdditionalBound:
& InterfaceType
& Cloneable
- это дополнительнаяBound, которая может использоваться только в дополнительномBoundList. ДополнительныйBoundList может использоваться только после ClassOrInterfaceType. И T1
является TypeVariable, а не ClassOrInterfaceType.
Итак, да, это ограничение синтаксиса Java.
Ответ 2
<T1,T2 extends Cloneable & T1> void f ( T1 t1, T2 t2 ){}
Я получаю сообщение "Интерфейс, ожидаемый здесь".
Из jls 4.4. Переменные типа:
Каждая переменная типа, объявленная как параметр типа, имеет привязку. Если нет bound объявлен для переменной типа, предполагается Object. Если связанная, он состоит из:
- a single type variable T, or
- a class or interface type T possibly followed by interface types `I1 & ... & In`.
Это ошибка времени компиляции, если любой из типов I1 ... In
является классомтипа или типа.
Итак, для выражения <T extends C & I> void test(T t)
, I
должен быть интерфейсом.