All About Generics in Java
All About Generics in Java
com/)
Generics
Introduced in J2SE 5.0, this long-awaited enhancement to the type system allows a type or method to operate on objects of
various types while providing compile-time type safety. It adds compile-time type safety to the Collections Framework and
eliminates the drudgery of casting. However, with the release of JDK6, generics can no longer be ignored. Simply put, if you
will be programming in Java6, you will be using generics.
Introduction
JDK 5.0 introduces several new extensions to the Java programming language. One of these is the
introduction of generics.
This trail is an introduction to generics. You may be familiar with similar constructs from other
languages, most notably C++ templates. If so, you'll see that there are both similarities and important
differences. If you are unfamiliar with look-a-alike constructs from elsewhere, all the better; you can
start fresh, without having to unlearn any misconceptions.
Generics allow you to abstract over types. The most common examples are container types, such as
those in the Collections hierarchy.
What if programmers could actually express their intent, and mark a list as being restricted to contain a
particular data type? This is the core idea behind generics. Here is a version of the program fragment
given above using generics:
List<Integer> myIntList = new LinkedList<Integer>(); // 1'
myIntList.add(new Integer(0)); // 2'
Integer x = myIntList.iterator().next(); // 3'
Notice the type declaration for the variable myIntList. It specifies that this is not just an arbitrary
List, but a List of Integer, written List<Integer>. We say that List is a generic interface that
takes a type parameter--in this case, Integer. We also specify a type parameter when creating the list
object.
Note, too, that the cast on line 3' is gone.
Now, you might think that all we've accomplished is to move the clutter around. Instead of a cast to
Integer on line 3, we have Integer as a type parameter on line 1'. However, there is a very big
difference here. The compiler can now check the type correctness of the program at compile-time.
When we say that myIntList is declared with type List<Integer>, this tells us something about the
This document is sole proprietary of Technical Lobby and any kind of misuse of this document is prohibited. This document should not be copied, modified
and re-created. Any such misuse will be entertained by Indian Copyright Law.
1
Technical Lobby, Raipur, Chhattisgarh, India (http://www.technicallobby.com/)
Generics
variable myIntList, which holds true wherever and whenever it is used, and the compiler will
guarantee it.
See the Examples – GenericsBasicExample.java
Defining Simple Generics
Here is a small excerpt from the definitions of the interfaces List and Iterator in package
java.util:
public interface List <E>{
void add(E x);
Iterator<E> iterator();
}
In the introduction, we saw invocations of the generic type declaration List, such as List<Integer>.
In the invocation (usually called a parameterized type), all occurrences of the formal type parameter (E
in this case) are replaced by the actual type argument (in this case, Integer).
You might imagine that List<Integer> stands for a version of List where E has been uniformly
replaced by Integer:
A generic type declaration is compiled once and for all, and turned into a single class file, just like an
ordinary class or interface declaration.
Line 1 is certainly legal. The trickier part of the question is line 2. This boils down to the question: is a
List of String a List of Object. Most people instinctively answer, "Sure!"
Well, take a look at the next few lines:
lo.add(new Object()); // 3
String s = ls.get(0); // 4: Attempts to assign an Object to a String!
This document is sole proprietary of Technical Lobby and any kind of misuse of this document is prohibited. This document should not be copied, modified
and re-created. Any such misuse will be entertained by Indian Copyright Law.
2
Technical Lobby, Raipur, Chhattisgarh, India (http://www.technicallobby.com/)
Generics
Here we've aliased ls and lo. Accessing ls, a list of String, through the alias lo, we can insert
arbitrary objects into it. As a result ls does not hold just Strings anymore, and when we try and get
something out of it, we get a rude surprise.
The Java compiler will prevent this from happening of course. Line 2 will cause a compile time error.
See Example – SubtypingErrorDemo.java
In general, if Foo is a subtype (subclass or subinterface) of Bar, and G is some generic type declaration,
it is not the case that G<Foo> is a subtype of G<Bar>. This is probably the hardest thing you need to
learn about generics, because it goes against our deeply held intuitions.
We should not assume that collections don't change. Our instinct may lead us to think of these things
as immutable.
For example, if the department of motor vehicles supplies a list of drivers to the census bureau, this
seems reasonable. We think that a List<Driver> is a List<Person>, assuming that Driver is a
subtype of Person. In fact, what is being passed is a copy of the registry of drivers. Otherwise, the
census bureau could add new people who are not drivers into the list, corrupting the DMV's records.
To cope with this sort of situation, it's useful to consider more flexible generic types. The rules we've
seen so far are quite restrictive.
Wildcards
Consider the problem of writing a routine that prints out all the elements in a collection. Here's how
you might write it in an older version of the language (i.e., a pre-5.0 release):
void printCollection(Collection c) {
Iterator i = c.iterator();
for (k = 0; k < c.size(); k++) {
System.out.println(i.next());
}
}
And here is a naive attempt at writing it using generics (and the new for loop syntax):
void printCollection(Collection<Object> c) {
for (Object e : c) {
System.out.println(e);
}
}
The problem is that this new version is much less useful than the old one. Whereas the old code could
be called with any kind of collection as a parameter, the new code only takes Collection<Object>,
which, as we've just demonstrated, is not a supertype of all kinds of collections!
This document is sole proprietary of Technical Lobby and any kind of misuse of this document is prohibited. This document should not be copied, modified
and re-created. Any such misuse will be entertained by Indian Copyright Law.
3
Technical Lobby, Raipur, Chhattisgarh, India (http://www.technicallobby.com/)
Generics
So what is the supertype of all kinds of collections? It's written Collection<?> (pronounced
"collection of unknown"), that is, a collection whose element type matches anything. It's called a
wildcard type for obvious reasons. We can write:
void printCollection(Collection<?> c) {
for (Object e : c) {
System.out.println(e);
}
}
and now, we can call it with any type of collection. Notice that inside printCollection(), we can
still read elements from c and give them type Object. This is always safe, since whatever the actual
type of the collection, it does contain objects. It isn't safe to add arbitrary objects to it however:
Collection<?> c = new ArrayList<String>();
c.add(new Object()); // Compile time error
Since we don't know what the element type of c stands for, we cannot add objects to it. The add()
method takes arguments of type E, the element type of the collection. When the actual type parameter
is ?, it stands for some unknown type. Any parameter we pass to add would have to be a subtype of
this unknown type. Since we don't know what type that is, we cannot pass anything in. The sole
exception is null, which is a member of every type.
On the other hand, given a List<?>, we can call get() and make use of the result. The result type is
an unknown type, but we always know that it is an object. It is therefore safe to assign the result of
get() to a variable of type Object or pass it as a parameter where the type Object is expected.
Bounded Wildcards
Consider a simple drawing application that can draw shapes such as rectangles and circles. To represent these
shapes within the program, you could define a class hierarchy such as this:
Generics
List<? extends Shape> is an example of a bounded wildcard. The ? stands for an unknown type,
just like the wildcards we saw earlier. However, in this case, we know that this unknown type is in fact
a subtype of Shape. (Note: It could be Shape itself, or some subclass; it need not literally extend
Shape.) We say that Shape is the upper bound of the wildcard.
There is, as usual, a price to be paid for the flexibility of using wildcards. That price is that it is now
illegal to write into shapes in the body of the method. For instance, this is not allowed:
This document is sole proprietary of Technical Lobby and any kind of misuse of this document is prohibited. This document should not be copied, modified
and re-created. Any such misuse will be entertained by Indian Copyright Law.
5
Technical Lobby, Raipur, Chhattisgarh, India (http://www.technicallobby.com/)
Generics
Bounded wildcards are just what one needs to handle the example of the DMV passing its data to the
census bureau. Our example assumes that the data is represented by mapping from names (represented
as strings) to people (represented by reference types such as Person or its subtypes, such as Driver).
Map<K,V> is an example of a generic type that takes two type arguments, representing the keys and
values of the map.
Again, note the naming convention for formal type parameters--K for keys and V for values.
Generic Methods
Consider writing a method that takes an array of objects and a collection and puts all objects in the
array into the collection. Here's a first attempt:
static void fromArrayToCollection(Object[] a, Collection<?> c) {
for (Object o : a) {
c.add(o); // Compile time error
}
}
By now, you will have learned to avoid the beginner's mistake of trying to use Collection<Object>
as the type of the collection parameter. You may or may not have recognized that using
Collection<?> isn't going to work either. Recall that you cannot just shove objects into a collection of
unknown type.
The way to do deal with these problems is to use generic methods. Just like type declarations, method
declarations can be generic--that is, parameterized by one or more type parameters.
We can call this method with any kind of collection whose element type is a supertype of the element
type of the array.
Object[] oa = new Object[100];
Collection<Object> co = new ArrayList<Object>();
This document is sole proprietary of Technical Lobby and any kind of misuse of this document is prohibited. This document should not be copied, modified
and re-created. Any such misuse will be entertained by Indian Copyright Law.
6
Technical Lobby, Raipur, Chhattisgarh, India (http://www.technicallobby.com/)
Generics
Notice that we don't have to pass an actual type argument to a generic method. The compiler infers the type
argument for us, based on the types of the actual arguments.
It is possible to use both generic methods and wildcards in tandem. Here is the method
Collections.copy():
class Collections {
public static <T> void copy(List<T> dest, List<? extends T> src) {
...
}
Note the dependency between the types of the two parameters. Any object copied from the source list,
src, must be assignable to the element type T of the destination list, dst. So the element type of src
can be any subtype of T --we don't care which.
Returning to our shape drawing problem, suppose we want to keep a history of drawing requests. We
can maintain the history in a static variable inside class Shape, and have drawAll() store its incoming
argument into the history field.
Generics
Generics Summary –
Using collections
Java's collections (in java.util.*) are pretty straightforward to use:
map2.put("xyz", array);
String s = map2.get("xyz").get(0); // No cast needed
Create and use a collection that can hold any type of object:
ArrayList<Object> list3 = new ArrayList<Object>();
list3.add("abc");
list3.add(5); // OK because "5" is autoboxed to "new Integer(5)"
Create and use a collection that can hold certain types of object:
ArrayList<Number> list4 = new ArrayList<Number>();
list4.add(5); // OK because class Integer extends class Number
list4.add(3.1416); // OK because class Double extends class Number
list4.add("abc"); // Error because String doesn't extend Number
You cannot create a collection of primitives:
ArrayList<int> foobar; // Error because an int isn't an Object
This document is sole proprietary of Technical Lobby and any kind of misuse of this document is prohibited. This document should not be copied, modified
and re-created. Any such misuse will be entertained by Indian Copyright Law.
8
Technical Lobby, Raipur, Chhattisgarh, India (http://www.technicallobby.com/)
Generics
java.lang.Object
extended by java.awt.Component
extended by java.awt.Container
extended by java.awt.Panel
extended by java.applet.Applet
extended by javax.swing.JApplet
This document is sole proprietary of Technical Lobby and any kind of misuse of this document is prohibited. This document should not be copied, modified
and re-created. Any such misuse will be entertained by Indian Copyright Law.
9
Technical Lobby, Raipur, Chhattisgarh, India (http://www.technicallobby.com/)
Generics
foo(new Bounded<Applet>()); // OK
foo(new Bounded<JApplet>()) // Not an Applet;
Generics
// This method takes a type parameter <T> at (1) and a regular parameter
// Tree<T> at (3), and returns a Set<T> at (2).
Create generic constructors:
class Something {
String s;
public <T> Something(T arg) {
s = arg.toString();
}
}
Create and implement generic interfaces:
interface Iface<T> {
void work(T arg);
}
class Impl<U> implements Iface<U> {
public void work(U arg) {
System.out.println(arg);
}
}
1. You cannot construct a new object of a parameterized type: T foo = new T();
2. You cannot create a new array of a parameterized type: T bar[] = new T[100];
...but wildcards are OK: Generics<?> ints[] = new Generics<?>[100];
4. You cannot ask about the generic type: list instanceof ArrayList<String>
class X<T> { static T foo; } //error! static variable with type parameter
not allowed
This document is sole proprietary of Technical Lobby and any kind of misuse of this document is prohibited. This document should not be copied, modified
and re-created. Any such misuse will be entertained by Indian Copyright Law.
11
Technical Lobby, Raipur, Chhattisgarh, India (http://www.technicallobby.com/)
Generics
This document is sole proprietary of Technical Lobby and any kind of misuse of this document is prohibited. This document should not be copied, modified
and re-created. Any such misuse will be entertained by Indian Copyright Law.
12