Можете ли вы указать общий тип, который подклассифицирует другой общий тип _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 должен быть интерфейсом.