Generics & Type Parameters

We can use generics and type parameters in many, many contexts -- but so that we can develop a concrete example, let us suppose that we are trying to implement a stack to store various objects. Indeed, perhaps we see in our future the need for a stack of Strings for one program, a stack of Files for another -- maybe even a stack of objects of type Card for a poker program.

Without type parameters (generics) we might try to implement separate stack classes for each type, but rewriting and maintaining such code is tedious and error-prone. (Note, we had no other way to do this until Java 1.5!)

We alternatively might try creating stacks where the elements were of Object type, but then the client has to deal with casting, which is error-prone. In particular, run-time errors can occur if types don't match, as shown below:

StackOfObjects s = new StackOfObjects();
Apple a = new Apple();
Orange b = new Orange();
s.push(a);
s.push(b);
a = (Apple) (s.pop()); // <-- this produces a run-time error

With generics, we avoid casting in the client, and type mismatch errors can be discovered at compile-time instead of run-time, as the below code demonstrates. Of course, as programmers, we always much prefer compile-time errors over run-time errors -- they are far easier to find and fix!

Stack<Apple> s = new Stack<Apple>();
Apple a = new Apple();
Orange b = new Orange();
s.push(a);
s.push(b); // <-- compile-time error
a = s.pop();

As can be seen above, we pass to the class Stack the type of object we require it to contain (i.e., "Apple") in between angle brackets.

To support this passing of a type parameter to the class, the first few lines of the Stack class might look something like this:

public class Stack<Item> implements Iterable<Item>{                                            
	private Item[] items;   // <-- we can use "Item" as a type now!
	private int size;
	
	public Stack() {
		//items = new Item[];  // <-- generic array creation is not allowed :o(
		items = (Item[]) (new Object[1]);  // <-- so we have to settle for this        
		size = 0; 
	}

       ...

The type Item above is replaced with whatever the client specified (Apple for instance) throughout the code. There are some exceptions, however. For example, generic array creation is not allowed in Java, so where we might want to do this: Items[] items = new Item[], we have to settle for a statement with a very ugly cast: Items[] items = (item[]) (new Object[1]);.