What are Generics and how can I use them?

Created May 8, 2012

Brandon Rohlfs

One of the biggest additions since the creation of the Collections framework is Generics.This long awaited update to the type system is a welcomed feature, which C++ developers have had in their toolbox for years using the STL. A generic type is defined using one or more type variables with it's contained methods using that type variable as a place holder to mark a parameter or return type. For instance the interface List has now been defined as.

So you might ask. What are Generics and why should I use them? Generics are a way to restrict a data structure to hold only a specific type thus providing compile time type checking. One of the added bonuses is that it is no longer necessary to cast a returned Object to a specific type because the compiler is aware of what type is being held by the Collection and what type is to be returned.

Generics do not share some of the things that are commonly held true in the Java
language and one of them is subtyping. One would assume the following perfectly legal since it is true that Object is a supertype of String. But the following is in fact illegal and will cause a compile time error.

List<Object> l = new ArrayList<String>();

As a rule. If X is a superclass or superinterface of Y and E is a generic type declaration then it not the case that E<X> is a supertype of E<Y>. So if E<Object> is not a super type of E<String> then what is the super type of E<String>? Read on and find out!

Wild Cards

Wild Cards represent what is called "the unknown type". Essentially they can be thought of as the supertype of any Collection. Wildcards allow some flexibility in certain situations where it is needed that a type be abstracted out. For instance what if we define the following method, printSet(Collection<Object> x). We just saw in the previous example that E<Object> is not the super type of E<String> or any other type for that matter. In this case we can change the printSet's parameter to Collection<?>. This allows us to pass in E<X> where X is any type.

assigning values is another matter. The add() method takes an argument of type E which is the type that the Collection is to hold. Any type wishing to be added to the Collection would have to be of the same type. Since<?> represents an unknown type it is impossible to determine what the type parameter of the collection represents.

Bounded Wildcards

A Bounded Wildcard allows as type to be constrained. Bounded Wildcards are useful when there is some type of partial knowledge about the type arguments. While it is still illegal to try and add an element to a unknown Collection with a bounded type they come in handy in other situations. One use is to be able to pass not only types into a method but sub-types also. In doing this we are able to implement polymorphic behavior.