Engineer
Engineer

Reputation: 8847

Multilevel Java generic inheritance using extends on generic parameters

I have

public class First<T> {}

public class Second<T extends SomeConcreteClass> extends First<T> {}

public class Third<T> extends Second<T> {} //Compile-time error

I get the compile-time error

Type argument T is not with bounds of type-variable T.

When I contruct a Third, I want to be able to give the generic parameter as SomeConcreteClass (or derived class thereof), and for a run-time error to be thrown if I've offered up a type that is not part of SomeConcreteClass's inheritance hierarchy.

I would think that the specification in Second's declaration would simply propagate downward, i.e. it should be implicit in the declaration (and any instantiations) of Third.

What's with the error?

Upvotes: 20

Views: 22372

Answers (4)

codeslapper
codeslapper

Reputation: 297

In our case you can probably replace this:

public class Third<T> extends Second<T> {}

with this:

public class Third extends Second<SomeConcreteClass> {}

To use the T within the constructor and otherwise within the code such as a member field of type T, then you can do like this:

VB2 extends VB1<Frag2>
...
public VB2(Frag2 frag){...

VB1<T extends Frag1> extends CommonVB<T>
...
public V1(T frag){... /// notice the T

CommonV<T extends CommonFragBase> extends BaseVB<T>
...
public CommonVB(T controller) {...

BaseVB<T extends CommonFragBase>

That works. The important thing is the generic on the concrete classes had to specify the actual concrete fragment class in order for the other code in the VB class to access its methods.

Upvotes: 2

maasg
maasg

Reputation: 37435

You have a downward propagation of the boundary restriction.

If you'd put your code above in generic terms, you will clearly see the restricted declaration. Also, any further inheritance would also need to preserve or further narrow down that restriction. eg :

public class First<T> {}

public class Second<U, T1 extends U> extends First<T1> {}

public class Third<V, T2 extends V> extends Second<V,T2> {} 

Note that it is now clear that you cannot have

public class Third<T> extends Second<T> {} 

As you are missing the required T2 type information for Second<V,T2>. When you use a concrete class, this restriction becomes implicit.

Upvotes: 1

Rob Wagner
Rob Wagner

Reputation: 4421

public class Third<T> extends Second<T> {}

This is a bound mismatch. You can't extend Second with a generic T when you have just specified that second is of type T than extends SomeConcreteClass. When you extend Second, you need to do so with something that is within the scope of SomeConcreteClass.

public class Third<T> extends Second<ClassThatExtendsSomeConcreteClass> {}

or just

public class Third<T> extends Second<SomeConcreteClass> {}

Upvotes: 0

Louis Wasserman
Louis Wasserman

Reputation: 198033

All you need is

public class Third<T extends SomeConcreteClass> extends Second<T>

You just need to respecify the bound. It doesn't propagate like you think it does.

(I'm not positive of the reason for this, but I have some guesses -- what if it was Third<T> extends Second<Foo<T>>? The appropriate bound on T isn't obvious, if there even is one. So instead, it just doesn't propagate automatically; you have to specify it.)

Upvotes: 24

Related Questions