Given the above classes, imagine a program that uses them to catalog information about a collection of books (and only books). Here is a code snippet from that program:public class Library { private List resources = new ArrayList(); public void addMedia(Media x) { resources.add(x); } public Media retrieveLast() { int size = resources.size(); if (size > 0) { return resources.get(size - 1); } return null; }}public class Media {}public class Book extends Media {}public class Video extends Media {}public class Newspaper extends Media {}
Type casting the return value from the//A Library containing only BooksLibrary myBooks = new Library();...Book lastBook = (Book)myBooks retrieveLast();
retrieveLast
method to
Book
is necessary, so the compiler knows what kind of object is returned and what kinds of operations can be performed on that object. Even though the programmer may be certain that only
Book
objects will be returned, the compiler does not know this. If a programming error did result in, say, a
Video
being stored in
myBooks
and then returned here, the cast would cause an unexpected exception to be thrown at runtime.
This is the primary reason that generic types and methods (often referred to, simply, as generics) were added to the Java language — to add compile-time type checking so the compiler can detect mismatched types at compile time, rather than runtime, when an exception is thrown.
Here is the same Library
class with a few simple changes (shown in bold), modified to use generics:
Library is now a generic type with a single type parameterpublic class Library<E> { private List resources = new ArrayList<E>(); public void addMedia(E x) { resources.add(x); } public E retrieveLast() { int size = resources.size(); if (size > 0) { return resources.get(size - 1); } return null; }}//The Media classes require no changes to use generics —//please refer to the original example.
E
. When using a generic type, specify a
type argument for each of its type parameters. A
Library
containing only
Book
objects, for example, would be written as
Library<Book>
. This is an example of a
parameterized type
. The code snippet now looks like this:
The type cast and the comment are no longer needed because theLibrary<Book> myBooks = new Library<Book>();...Book lastBook = myBooks retrieveLast();
Library
instance has been constrained to deal with
Book
objects. The compiler now understands that this particular instance of
Library
contains
Book
s. If the compiler detects that the
Library
is being used inappropriately — trying to add or retrieve a
Newspaper
, for example — it generates an error.
Later on our imaginary program includes the following line of code:
Without generics, the compiler couldn't warn you ifmyBooks.addMedia(myFavoriteBook);
myFavoriteBook
is of the wrong type. If it is a
String
, for example, a runtime exception would occur somewhere down the road after someone invokes
retrieveLast
. These sorts of errors can be especially hard to debug, since the runtime error may occur at a point in the code far removed from the actual programming error that caused it. With generics, the compiler calls out the error right away. You find out about the programming error immediately, and are shown exactly where the problem lies.
You can further refine the declaration of Library
to use Library<E extends Media>
. The compiler will enforce the constraint that a Library
can only contain Media
objects (and not, say, Number
s).
If you use any of the Java programming libraries that deal with groups of data, such as classes or interfaces that deal with collections, lists, arrays, and vectors, you will notice that they make extensive use of generics.
Note: When compiling code that refers to generics, you might encounter a message like this:This error means that you have bypassed generics and have lost the benefit of compile-time type checking. You should fix your code to make full use of generics and take advantage of compile-time type checking.Note: MyFile.java uses unchecked or unsafe operations.Note: Recompile with -Xlint:unchecked for details.As mentioned in the text of the sample error, using the
-Xlink:unchecked
javac
option gives you the most information available about unchecked or type unsafe operations.
This covers a simple case of using a generic class. Subsequent sections go into generic types in more detail and touch on generic methods.