Tag: Generics and Interface

Java Generics and Collections

July 3, 2008

I hate these situations in coding where common sense fails you. You are supposed to know anything and everything of the language.

Suppose we have an interface Bounceable, and Baloon and GolfBall are two classes that implement the bounce() method of the interface.

public interface Bounceable {
     void bounce();
public class Baloon  implements Bounceable {
     public void bounce() {
          System.out.println("I am a Baloon");
public class GolfBall implements Bounceable {
     public void bounce() {
          System.out.println("I am a GolfBall");

We have a class Person, which takes a list of Bounceable objects and plays them.

public class Person {
     public void playAll(List<Bounceable> bList) {
          for(Bounceable b : bList) {
               System.out.println("Bounceable object: " + b);

Now, from a main method, lets try to test something. First, lets create a list of Bounceable objects and pass it to the playAll() method of the Person object.

List<Bounceable> bList = new ArrayList<Bounceable>();
bList.add(new Baloon());
bList.add(new SoccerBall());
bList.add(new GolfBall());
Person person = new Person();

This works great. The playAll() method is expecting


and we just passed bList to it. Perfect!

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.

Baloon implements Bounceable. So lets try to create a


and pass it to the


method. But this simply doesn’t work.

List<Baloon> baloonList = new ArrayList<Baloon>();
baloonList.add(new Baloon());
baloonList.add(new Baloon());
baloonList.add(new Baloon());

This is because once we are in the

playAll(List<Bounceable> bList)

method, the list is treated as


and we should be able to add any objects of type Bounceable.

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

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


, you cannot pass a

List<y extends X>

, because the compiler is scared that you will take the


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


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


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.