JDK 1.5 allows you to declare generic classes, interfaces, and methods . Several interfaces and classes in the Java API are modified using generics. For example, the java.lang.Comparable interface was declared as shown in Figure 21.1(a) prior to JDK 1.5, but is modified as shown in Figure 21.1(b) in JDK 1.5.
Here, <T> represents a formal generic type , which can be substituted with an actual concrete type later. Substituting a generic type is called a generic instantiation . By convention, a single capital letter such as E or T is used to denote a formal generic type.
The statement in Figure 21.2(a) declares that c is a reference variable whose type was Comparable prior to JDK 1.5 and invokes the compareTo method to compare a Date object with a string. The code compiles fine, but has a runtime error because a string cannot be compared with a date.
The statement in Figure 21.2(b) declares that c is a reference variable whose type is Comparable<Date> in JDK 1.5 and invokes the compareTo method to compare a Date object with a string. The code has a compile error, because the argument passed to the compareTo method must be of the Date type. Since the errors can be detected at compile time rather than at runtime, the generic type makes the program more reliable .
Note
Generic types must be reference types. You cannot substitute a generic type with a primitive type such as int , double , or char . |
ArrayList was introduced in §9.9, "The ArrayList Class." This class is a generic class in JDK 1.5. Figure 21.3 shows the class diagrams for ArrayList prior to JDK 1.5 and in JDK 1.5, respectively.
For example, the following statement creates a list for strings:
ArrayList<String> list = new ArrayList<String>();
You can now add only strings into the list. For example,
list.add( "Red" );
If you attempt to add a non-string, a compile time error will occur. For example, the following statement is now illegal because list can only contain strings:
list.add( new Integer( 1 ));
Casting is not needed to retrieve a value from a list with a specified element type because the compiler already knows the element type. For example, the following statements create a list that contains only double values, add elements to the list, and retrieve elements from the list:
1 ArrayList<Double> list = new ArrayList<Double>(); 2 list.add( 5.5 ); // 5.5 is automatically converted to new Double(5.5) 3 list.add( 3.0 ); // 3.0 is automatically converted to new Double(3.0) 4 Double doubleObject = list.get( ); // No casting is needed 5 double d = list.get( 1 ); // Automatically converted to double
In lines 2 and 3, 5.5 and 3.0 are automatically converted into Double objects and added to list . In line 4, the first element in list is assigned to a Double variable. No casting is necessary because list is declared for Double objects. In line 5, the second element in list is assigned to a double variable. The object in list.get(1) is automatically converted into a primitive type value.