简体   繁体   中英

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> 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?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM