Generics Introduction

Why Generics?

Before Java 5...we use the Object class so that your Bag can hold any type of object.

public class Bag { 
    private Object item; 
    public void   setItem( Object x ) { item = x; } 
    public Object getItem()           { return item; } 
} 

Then to create an instance of bag...

Bag b = new Bag(); 
String s = "I'm a kitty cat!";
b.setItem( s ); 
String contents = (String) b.getItem();

Two problems with this:

  1. Cast to String is annoying, we know it's a String already! But we need it for type safety check at compile time when doing the String contents assignment, because compiler only knows that getItem() returns an Object.
  2. getItem() might actually be returning something other than a String! Since it is only required that item be an Object, if the Bag actually contained other types of non-String Objects, then something other than a String would have been returned, and contents assignment would have failed at runtime, but not at compile time.

Generics

Available in Java 5 and above, generics allow classes and interfaces to have a type parameter, to specify the types of variables, return values, parameters, etc. in the members of that class/interface.

So for Bag, we can specify that we only want it to store items of a specific type, as follows.

In the class definition:

public class Bag<E> { 
  private E item; 
  public void setItem(E x) { item = x; } 
  public E getItem() { return item; } 
} 

In the instantiation:

Bag<String> b = new Bag<String>(); 
b.setItem("How about that?"); 
String contents = b.getItem(); 

As for interfaces:

 // From Project 1
public interface GStack<T> {
    public boolean isEmpty();
    public void push(T d);
    public T pop();
    public T peek();
}

Then, the declaration of a class implementing this interface would look something like this:

  public class MyClass<T> implements GStack<T> {
    // your code here....
  }

Now, we've solved our problems...

  1. No need to worry about casting.
  2. Compiler can guarantee type correctness at run time (whereas before, we were relying on the programmer to be sure bad casts weren't happening). So, fewer ClassCastExceptions!!!

Under the hood: Type Erasure

Unfortunately, this means that pre-Java 5 code written with generics might not work, so executed code & JVM is still pre-generics Java:

Creating Generic Arrays in Java

In project 1 you'll need to create a generic array, but doing so in Java might not work as you expect. Let's say E is your type variable. To make an array, you might want to do:

  E[] myGenericArray=new E[128];

But this gives a compilation error: Cannot create a generic array of E

To get around this, you can create an Object array and cast it, like this:

  E[] myGenericArray=(E[])new Object[128];

You should then be able to use the generic array just as you'd expect.

Practice

Let's try it out in today's worksheet, Bag.java.

Extra Resources