Since Bounceable is an interface, now we would also hope that it would accept List of any subclasses of Bounceable. At least, thats what I have known of polymorphism in Java. And it works that way with Arrays. However, thats not the case with Generics and Collections.

// See, we just corrupted the baloon list with a golf ball.
baloonList.add(new GolfBall());

Put simply, if a method foo() takes an argument

List<x>

, you cannot pass a

List<y extends X>

, because the compiler is scared that you will take the

List<x>

and put stuffs into it that aren’t of type Y, thus corrupting the entire list type.

But there is a way that you are allowed to pass

List<Baloon>

it to the method, but you cannot modify the list. For that we have to change our method signature to:

playAll(List<? extends Bounceable> bList)

? extends X means any unspecified type of X. So we can pass

List<Baloon>

to the method with signature

List<? extends Bounceable>

and retrieve our Baloon objects back in the playAll() method, because the compiler knows that we aren’t allowed to add anything to the Baloon List.

Sigh!!!!! Interesting, isn’t it? While Generics is great feature for type safety, the way this feature is inconsistent with other features within java makes it very difficult for beginners and students to learn and feel confident about the language. With Generics, Java just turned into big and too confusing of a language.