Search code examples
javagenericsscjp

Generic type parameters bounds and concrete class


From page 49 of OCP Java SE 6 Programmer Practice Exams, question 11. We are given such code:

class A { }
class B extends A { }
class C extends B { }
public class Carpet<V extends B> {
    public <X extends V> Carpet<? extends V> method(Carpet<? super X> e) {
        // insert code here
    }
}

And we are asked: Which, inserted independently at marked line, will compile?

So, I'm testing the first answer - return new Carpet<X>(). It works. Ok, my reasoning goes like well, if I have a return type of Carpet<? extends V>, it must return something that extends V. Just before it's written, that X extends V, so that's perfect, X works.

Next answer - return new Carpet<V>(). Well, this is even simpler, because V already "extends" V, so I can return that. It works, ok, good.

Next - return new Carpet<A>(). This is not working, compiler is shouting:

Type parameter 'A' is not within its bound; should extend 'B'

But, I agree. It's written near the class declaration, V extends B. So, I understand I can return something that extends V, which extends B. For sure not A.

So, I see the next answer - return new Carpet<B>(). Phew, easy, the compiler just said "should extend B, so B (like before V for "something that extends V") should be just perfect. But! It's not compiling:

Error:(6, 16) java: incompatible types
  required: Carpet<? extends V>
  found:    Carpet<B>

I don't understand why. Explanation given in book is:

It's illegal to use a concrete class type since the exact scope of V is unknown.

But frankly, I still don't get it. I'm not sure what the "exact scope" in that context means, but the compiler said, that return type parameter should extend B. So, he is able to figure it out (like me) that "something that extends V" is "something that extends B". So, why B is not working?

Could you please provide better explanation?


Solution

  • V is the generic type of Carpet. When instantiating a Carpet, the user of the class chooses the concrete type of V. It could be B, or C, or any other class that extends B directly or indirectly:

    Carpet<B> carpetOfB = new Carpet<B>();
    

    or

    Carpet<C> carpetOfC = new Carpet<C>();
    

    or

    Carpet<Plane> carpetOfPlane = new Carpet<Plane>();
    

    Whatever the user chooses as concrete type for V (let's say he chooses Plane, which extends C), the method must return a Carpet of a type that extends V. So, in this case, this type must be Plane or a subtype of Plane. And clearly, B doesn't qualify, since it doesn't extend Plane.