Home arrow Java arrow Page 3 - Generics in Java
JAVA

Generics in Java


Generics are the most important change to the Java language in a long time, possibly since it was created. They make reusable Java code easier to write and read. This article, the first in a series, was excerpted from chapter eight of the book Learning Java, third edition, written by Patrick Niemeyer and Jonathan Knudsen (O'Reilly; ISBN: 0596008732). Copyright 2006 O'Reilly Media, Inc. All rights reserved. Used with permission from the publisher. Available from booksellers or direct from O'Reilly Media.

Author Info:
By: O'Reilly Media
Rating: 4 stars4 stars4 stars4 stars4 stars / 11
May 10, 2007
TABLE OF CONTENTS:
  1. · Generics in Java
  2. · Containers: Building a Better Mousetrap
  3. · Enter Generics
  4. · There Is No Spoon
  5. · Erasure

print this article
SEARCH DEVARTICLES

Generics in Java - Enter Generics
(Page 3 of 5 )

Generics in Java are an enhancement to the syntax of classes that allow us to specialize the class for a given type or set of types. A generic class requires one or more type parameters wherever we refer to the class type and uses them to customize itself.

If you look at the source or Javadoc for the List class, for example, you'll see it defined something like this:

  public class List< E > {
   
...
   
public void add( E element ) { ... }     public E get( int i ) { ... }
 
}

The identifier E between the angle brackets (<>) is a type variable. It indicates that the class List is generic and requires a Java type as an argument to make it complete. The name E is arbitrary, but there are conventions that we'll see as we go on. In this case, the type variable E represents the type of elements we want to store in the list. The List class refers to the type variable within its body and methods as if it were a real type, to be substituted later. The type variable may be used to declare instance variables, arguments to methods, and the return type of methods. In this case, E is used as the type for the elements we'll be adding via the add() method and the return type of the get() method. Let's see how to use it.

The same angle bracket syntax supplies the type parameter when we want to use the List type:

  List<String> listOfStrings;

In this snippet, we declared a variable called listOfStrings using the generic type List with a type parameter of String. String refers to the String class, but we could have specialized List with any Java class type. For example:

  List<Date> dates;  
  List<java.math.BigDecimal> decimals;  
  List<Foo> foos;

Completing the type by supplying its type parameter is called instantiating the type. It is also sometimes called invoking the type, by analogy with invoking a method and supplying its arguments. Whereas with a regular Java type, we simply refer to the type by name, a generic type must be instantiated with parameters wherever it is used.* Specifically this means we must instantiate the type everywhere types can appear: as the declared type of a variable (as shown in this code snippet), as the type of a method argument, as the return type of a method, or in an object allocation expression using the new keyword.

Returning to our listOfStrings, what we have now is effectively a List in which the type String has been substituted for the type variable E in the class body:

  public class List< String > {
   
...
   
public void add( String element ) { ... }
   
public String get( int i ) { ... }
 
}

We have specialized the List class to work with elements of type String and only elements of type String. This method signature is no longer capable of accepting an arbitrary Object type.

List is just an interface. To use the variable, we'll need to create an instance of some actual implementation of List. As we did in our introduction, well use ArrayList. As before, ArrayList is a class that implements the List interface, but, in this case, both List and ArrayList are generic classes. As such, they require type parameters to instantiate them where they are used. Of course, well create our ArrayList to hold String elements to match our List of Strings:

  List<String> listOfStrings = new ArrayList<String>();

There is no new syntax in this example. As always, the new keyword takes a Java type and parentheses with possible arguments for the class's constructor. In this case, the type is ArrayList<String>--the generic ArrayList type instantiated with the String type.

We can now use our specialized List with strings. The compiler prevents us from even trying to put anything other than a String object (or a subtype of String if there were any) into the list and allows us to fetch them with the get() method without requiring any cast:

  List<String> listOfStrings = new ArrayList<String>();
  listOfStrings.add("eureka! ");
  String s = listOfStrings.get(0); // "eureka! "

  listOfStrings.add( new Date() ); // Compile-time Error!

Let's take another example from the Collections API. The Map interface provides a dictionary-like mapping that associates key objects with value objects. Keys and values do not have to be of the same type. The generic Map interface requires two type parameters: one for the key type and one for the value type. The Javadoc looks like this:

  public class Map< K, V > {
    ...
    public V put( K key, V value ) { ... } // returns any old value
    public V get( K key ) { ... }
  }

We can make a Map that stores Employee objects by Integer "employee id" numbers like this:

  Map< Integer, Employee > employees = new HashMap< Integer, Employee >();
  Integer bobsId = ...;
  Employee bob = ...;

  employees.put( bobsId, bob );
  Employee employee = employees.get( bobsId );

Here, we used HashMap, which is a generic class that implements the Map interface, and instantiated both types with the type parameters Integer and Employee. The Map now works only with keys of type Integer and holds values of type Employee.

The reason we used Integer here to hold our number is that the type parameters to a generic class must be class types. We can't parameterize a generic class with a primitive type, such as int or boolean. Fortunately, autoboxing of primitives in Java 5.0 (see Chapter 5) makes it appear almost as if we can, by allowing us to use primitive types as if they were wrapper types:

  employees.put( 42, bob );
  Employee bob = employees.get( 42 );

Here, autoboxing converted the integer 42 to an Integer wrapper for us twice.

In Chapter 11, we'll see that all of the Java collection classes and interfaces have been made generic in Java 5.0. Furthermore, dozens of other APIs now use generics to let you adapt them to specific types. We'll talk about them as they occur throughout the book.

Talking About Types

Before we move on to more important things, we should say a few words about the way we describe a particular parameterization of a generic class. Since the most common and compelling case for generics is for container-like objects, it's common to think in terms of a generic type "holding" a parameter type. In our example, we called our List<String> a "list of strings" because, sure enough, that's what it was. Similarly, we might have called our employee map a "Map" of employee ids to Employee objects." However, these descriptions focus a little more on what the classes do than on the type itself. Take instead a single object container called Trap< E > that could be instantiated on an object of type Mouse or of type Bear, that is, Trap<Mouse> or Trap<Bear>. Our instinct is to call the new type a "mouse trap" or "bear trap." Similarly, we could have thought of our list of strings as a new type: "string list" or our employee map as a new "integer employee object map" type. There is no harm in using whatever verbiage you prefer, but these latter descriptions focus more on the notion of the generic as a type and may help a little bit later when we have to discuss how generic types are related in the type system. There we'll see that the container terminology turns out to be a little counterintuitive.

In the following section, we'll carry on our discussion of generic types in Java from a different perspective. We've seen a little of what they can do; now we need to talk about how they do it.


blog comments powered by Disqus
JAVA ARTICLES

- Java Too Insecure, Says Microsoft Researcher
- Google Beats Oracle in Java Ruling
- Deploying Multiple Java Applets as One
- Deploying Java Applets
- Understanding Deployment Frameworks
- Database Programming in Java Using JDBC
- Extension Interfaces and SAX
- Entities, Handlers and SAX
- Advanced SAX
- Conversions and Java Print Streams
- Formatters and Java Print Streams
- Java Print Streams
- Wildcards, Arrays, and Generics in Java
- Wildcards and Generic Methods in Java
- Finishing the Project: Java Web Development ...

Watch our Tech Videos 
Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 
Support 

Developer Shed Affiliates

 




© 2003-2017 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap
Popular Web Development Topics
All Web Development Tutorials