15

I have a family of domain models, each of which has a subclass that extends it and implements a specific interface, like this (Cloneable is not the interface in question, it's for example purposes only):

class A{}
class B extends A implements Cloneable{}

class C{}
class D extends C implements Cloneable{}

I want to create a generic type signature that will enforce this pairing, I've tried this which FAILS:

<T1,T2 extends T1 & Cloneable> void f ( T1 t1, T2 t2 ){}

but I get message in my IntelliJ IDE "Type parameter cannot be followed by other bounds"; it still FAILS if I switch the order around to:

<T1,T2 extends Cloneable & T1> void f ( T1 t1, T2 t2 ){}

I get the message "Interface expected here."

Confusingly, both of these signatures WORK:

<T extends A & Cloneable> void f( A a, T t ){}
<T1,T2 extends T1> void f ( T1 t1, T2 t2 ){}

Is this just a weird limitation of Java's generic type system that I cannot have a generic class (ie T2) extend both another generic class (ie T1) and a concrete interface (eg Cloneable)?

tl;dr: So, why won't <T1,T2 extends Cloneable & T1> void f ( T1 t1, T2 t2 ){} compile: is it a limitation of the Java generic syntax or am I using the wrong syntax?

Sled
  • 18,541
  • 27
  • 119
  • 168
  • possible duplicate of [Java generics - Make Generic to extends 2 interfaces](http://stackoverflow.com/questions/13101991/java-generics-make-generic-to-extends-2-interfaces) and [Why can't I use a type argument in a type parameter with multiple bounds?](http://stackoverflow.com/questions/197190/why-cant-i-use-a-type-argument-in-a-type-parameter-with-multiple-bounds) – Paul Bellora Nov 14 '13 at 17:39
  • Yes, another weird and unfortunate limitation of Java typing that you can't do intersection type constraints if a type variable is involved. The reason given is apparently to avoid "certain problematic cases". – Judge Mental Nov 14 '13 at 17:39
  • @PaulBellora While the answer may be the same, my question is different from the one of two interfaces. – Sled Nov 14 '13 at 17:42
  • @JudgeMental It seems compile time checkable so I really would be curious to the actual specifics involved. – Sled Nov 14 '13 at 17:42
  • 1
    @ArtB See the edit to that question (which had a bounty) and my answer. It's a little confusing I know. The second linked post is more obviously a duplicate. – Paul Bellora Nov 14 '13 at 18:11

2 Answers2

6

The answer is in JLS 4.4:

TypeParameter:
    TypeVariable TypeBoundopt

TypeBound:
    extends TypeVariable
    extends ClassOrInterfaceType AdditionalBoundListopt

AdditionalBoundList:
    AdditionalBound AdditionalBoundList
    AdditionalBound

AdditionalBound:
    & InterfaceType

The & Cloneable is an AdditionalBound, which can only be used in an AdditionalBoundList. An AdditionalBoundList can only be used after ClassOrInterfaceType. And T1 is a TypeVariable, not a ClassOrInterfaceType.

So, yes, it's a limitation of the Java generic syntax.

yshavit
  • 42,327
  • 7
  • 87
  • 124
0

<T1,T2 extends Cloneable & T1> void f ( T1 t1, T2 t2 ){}

I get the message "Interface expected here."

From the jls 4.4. Type Variables:

Every type variable declared as a type parameter has a bound. If no bound is declared for a type variable, Object is assumed. If a bound is declared, it consists of either:

- a single type variable T, or

- a class or interface type T possibly followed by interface types `I1 & ... & In`.

It is a compile-time error if any of the types I1 ... In is a class type or type variable.

So, for an expression <T extends C & I> void test(T t), I should be an interface.

Sage
  • 15,290
  • 3
  • 33
  • 38
  • `I` in the original question was `Cloneable`, which is an interface. The problem was in the `C`, which must be a class or interface (but not a type variable). – yshavit Nov 14 '13 at 18:41
  • @yshavit, please, take a look at the start of my answer, where i quoted one of his question. He actually had two question. I pasted the question with `>` code by with `<` it was hiding the `` part in the post. :) – Sage Nov 14 '13 at 18:48
  • don't be, it is my fault that i could not paste it correctly :) – Sage Nov 14 '13 at 19:23