Home : Course Map : Chapter 10 : Java :
Generics - J2SE5.0
JavaTech
Course Map
Chapter 10

Introduction
Vector/Enumeration
Hashtable,HashMap
   Properties
Collections

Iterator/ArrayList
Generics
Preferences API
  Demo 1
Concurrency Utils
Enumerated Type
Arrays Class
String Tools
  String
  StringBuffer
  StringBuilder
  StringTokenizer
  String.split()

Calendar,Date,Time
  Demo 2
  Demo 3

Other Utilities
Exercises

    Supplements
Performance
Benchmarks
     About JavaTech
     Codes List
     Exercises
     Feedback
     References
     Resources
     Tips
     Topic Index
     Course Guide
     What's New

In the Collections discussion we noted that object containers expect to hold java.lang.Object types and that the returned Object types must be cast into the desired type. The new J2SE 5.0 includes the very significant addition of generics feature in which object containers can actually know what object type they should hold. Then any attempt to insert an object of the wrong type results in a compile-time error rather than a runtime ClassCastException.

Generics is a large an important addition to Java, and we only scratch the surface of how to use generics. Generic features pervade all the Collection Framework classes as well as several other APIs in J2SE 5.0.

We use the ArrayList class to illustrate the generics capability. Suppose we have a list of strings

List list_of_strings = new ArrayList ();

Without generics, we can insert any Object type into the list - String, Integer, etc. With generics, we declare the type of object the list is allowed to contain at compile time. The syntax is as follows:

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

The <String> notation indicates that this particular List object is only allowed to contain String types. Any attempt to add an Integer (autoboxed or not) or any other object type is disallowed at compile time.

list_of_strings.add ("this is legal");
list_of_strings.add (new Integer (5)); // this is not allowed
list_of_strings.add (5); // neither is this

In the first illegal add(), we explicitly wrap the 5 into an Integer. Integer is an Object type and so could be added to a plain List, but it is not permitted to be added to the List<String> object container.In the second attempt, neither is the int 5 permitted. The compiler errors you will see look like this:

Generics.java:7: cannot find symbol
symbol : method add (java.lang.Integer)
location: interface java.util.List<java.lang.String>
        list.add (new Integer (5));
            ^
Generics.java:8: cannot find symbol
symbol : method add (int)
location: interface java.util.List<java.lang.String>
        list.add (5);
            ^

The compiler is saying that it cannot find an add() method that takes an Integer type in the interface java.util.List. And it says there is not an add() that takes an int.

By adding the generic type notation (also known as a parameterized type) we have effectively created a new List interface that permits only String inserts. (Note that the second illegal add() did not autobox the int 5 into an Integer. Doing so would not have worked either since the first illegal attempt already demonstrated that adding an Integer is not permitted.)

Where generics becomes important and saves a lot of code is when iterating over generic types and, in particular, in conjunction with autoboxing and unboxing of primitive types. Recall that without generics we must cast returned Object types into the desired type during an iteration. That was with J2SE 1.4 and below. With J2SE 5.0, the collection object "knows" what type it holds, so it returns that type instead of the Object type.

Without generics, iterating through a list of strings and printing each out required code like this

List list_of_strings = new ArrayList ();
...
for (Iterator it = list_of_strings.iterator (); it.hasNext ();) {
  String s = (String) it.next ();
  Sytem.out.println (s);
}

But when list_of_strings is a List type, this simplifies to

for (Iterator it = list_of_strings.iterator (); it.hasNext ()) {
    String s = it.next ();
    Sytem.out.println (s);
}

We see that no explicit casting is needed.

With autoboxing and unboxing, we can insert and retrieve primitive types without explicitly using the wrapper objects.

List<Integer> list_of_ints = new ArrayList<Integer> ();
...
for (Iterator it = list_of_ints.iterator (); it.hasNext ();) {
    int i = it.next ();
   ...
}

We should warn you of a nuisance with the J2SE 5.0 compiler. The use of these special type-safe containers removes a significant source of errors. For backward compatibility, all the old containers are still available. So any pre-5.0 code continues to work exactly the same in 5.0 and beyond. However, because the old container types are potentially unsafe, the 5.0 javac compiler now issues warnings about possible unsafe usage whenever it encounters one of the old container types.

These are just warnings and can be ignored if you are sure that the code is safe. The best way to get rid of the warnings is to switch to the use of the generic types where appropriate.

Of course, sometimes the old non-type-safe containers are needed, such as when you really want to insert a mix of object types. In this case, you can just ignore the warnings. Alternatively, the metadata (annotation) system discussed in Chapter 1: Supplements and Chapter 4: Supplements provides an @SuppressWarnings annotation to explicitly suppress such warnings.

Generics and the Enhanced For-Loop.

Note that generics allows for the enhanced for loop (or for-each loop) discussed in Chapter 2: Supplements. to work with Collections containers. It offers an elegant alternative to the Iterator type loop in many cases. For example, the following snippet

  ArrayList<string> array_list = new ArrayList<string> ();
  array_list.add ("Abc");
  array_list.add ("Def");
  array_list.add ("Ghi");

  for (String str : array_list)
    System.out.println (str);

gives an output as follows:

  Abc
  Def
  Ghi

Specifying the ArrayList variable as a String container means that the string parameter in the loop will always be assigned the correct type.

References & Web Resources


Latest update: Oct. 19, 2005

              Tech
ArbitaryPrecision
   BigInteger
  
BigDecimal
Bit Handling
Exercises

           Physics
Data Gen&Analysis

  Demo 1
  Demo 2
Exercises

  Part I Part II Part III
Java Core 1  2  3  4  5  6  7  8  9  10  11  12 13 14 15 16 17
18 19 20
21
22 23 24
Supplements

1  2  3  4  5  6  7  8  9  10  11  12

Tech 1  2  3  4  5  6  7  8  9  10  11  12
Physics 1  2  3  4  5  6  7  8  9  10  11  12

Java is a trademark of Sun Microsystems, Inc.