Additional Compile-Time Translation Issues: Methods That Use a Type Parameter as the Return Type

Additional Compile Time Translation Issues Methods That Use a Type Parameter as the Return Type

Let's consider a generic method example in which type parameters are used in the return type and in the parameter list (Fig. 18.5). The application uses a generic method maximum to determine and return the largest of its three arguments of the same type. Unfortunately, the relational operator > cannot be used with reference types. However, it is possible to compare two objects of the same class if that class implements the generic interface Comparable< T > (package java.lang). All the type-wrapper classes for primitive types implement this interface. Like generic classes, generic interfaces enable programmers to specify, with a single interface declaration, a set of related types. Comparable< T > objects have a compareTo method. For example, if we have two Integer objects, integer1 and integer2, they can be compared with the expression:

 integer1.compareTo( integer2 )

 

Figure 18.5. Generic method maximum with an upper bound on its type parameter.

(This item is displayed on page 877 in the print version)

 1 // Fig. 18.5: MaximumTest.java
 2 // Generic method maximum returns the largest of three objects.
 3
 4 public class MaximumTest
 5 {
 6 // determines the largest of three Comparable objects 
 7 public static < T extends Comparable< T > > T maximum( T x, T y, T z )
 8 { 
 9  T max = x; // assume x is initially the largest 
10 
11  if ( y.compareTo( max ) > 0 ) 
12  max = y; // y is the largest so far 
13 
14  if ( z.compareTo( max ) > 0 ) 
15  max = z; // z is the largest 
16 
17  return max; // returns the largest object 
18 } // end method maximum 
19
20 public static void main( String args[] )
21 {
22 System.out.printf( "Maximum of %d, %d and %d is %d

", 3, 4, 5,
23 maximum( 3, 4, 5 ) );
24 System.out.printf( "Maximum of %.1f, %.1f and %.1f is %.1f

",
25 6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ) );
26 System.out.printf( "Maximum of %s, %s and %s is %s
", "pear",
27 "apple", "orange", maximum( "pear", "apple", "orange" ) );
28 } // end main
29 } // end class MaximumTest
 
Maximum of 3, 4 and 5 is 5

Maximum of 6.6, 8.8 and 7.7 is 8.8

Maximum of pear, apple and orange is pear
 

It is the responsibility of the programmer who declares a class that implements Comparable< T > to declare method compareTo such that it compares the contents of two objects of that class and returns the results of the comparison. The method must return 0 if the objects are equal, -1 if object1 is less than object2 or 1 if object1 is greater than object2. For example, class Integer's compareTo method compares the int values stored in two Integer objects. A benefit of implementing interface Comparable< T > is that Comparable< T > objects can be used with the sorting and searching methods of class Collections (package java.util). We discuss those methods in Chapter 19, Collections. In this example, we'll use method compareTo in method maximum to help determine the largest value.

Generic method maximum (lines 718) uses type parameter T as the return type of the method (line 7), as the type of method parameters x, y and z (line 7), and as the type of local variable max (line 9). The type parameter section specifies that T extends Comparable< T >only objects of classes that implement interface Comparable< T > can be used with this method. In this case, Comparable is known as the upper bound of the type parameter. By default, Object is the upper bound. Note that type parameter declarations that bound the parameter always use keyword extends regardless of whether the type parameter extends a class or implements an interface. This type parameter is more restrictive than the type parameter specified for printArray in Fig. 18.3, which was able to output arrays containing any type of object. The restriction of using Comparable< T > objects is important because not all objects can be compared. However, Comparable< T > objects are guaranteed to have a compareTo method.

Method maximum uses the same algorithm that we used in Section 6.4 to determine the largest of its three arguments. The method assumes that its first argument (x) is the largest and assigns it to local variable max (line 9). Next, the if statement at lines 1112 determines whether y is greater than max. The condition invokes y 's compareTo method with the expression y.compareTo( max ), which returns -1, 0 or 1, to determine y 's relationship to max. If the return value of the compareTo is greater than 0, then y is greater and is assigned to variable max. Similarly, the if statement at lines 1415 determines whether z is greater than max. If so, line 15 assigns z to max. Then, line 17 returns max to the caller.

In main (lines 2028), line 23 calls maximum with the integers 3, 4 and 5. When the compiler encounters this call, it first looks for a maximum method that takes three arguments of type int. There is no such method, so the compiler looks for a generic method that can be used and finds generic method maximum. However, recall that the arguments to a generic method must be of a reference type. So the compiler autoboxes the three int values as Integer objects and specifies that the three Integer objects will be passed to maximum. Note that class Integer (package java.lang) implements interface Comparable< Integer > such that method compareTo compares the int values in two Integer objects. Therefore, Integers are valid arguments to method maximum. When the Integer representing the maximum is returned, we attempt to output it with the %d format specifier, which outputs an int primitive type value. So maximum's return value is output as an int value.

A similar process occurs for the three double arguments passed to maximum in line 25. Each double is autoboxed as a Double object and passed to maximum. Again, this is allowed because class Double (package java.lang) implements the Comparable< Double > interface. The Double returned by maximum is output with the format specifier %.1f, which outputs a double primitive type value. So maximum's return value is auto-unboxed and output as a double. The call to maximum in line 27 receives three Strings, which are also Comparable< String > objects. Note that we intentionally placed the largest value in a different position in each method call (lines 23, 25 and 27) to show that the generic method always finds the maximum value, regardless of its position in the argument list.

When the compiler translates generic method maximum into Java bytecodes, it uses erasure (introduced in Section 18.3) to replace the type parameters with actual types. In Fig. 18.3, all generic types were replaced with type Object. Actually, all type parameters are replaced with the upper bound of the type parameterunless specified otherwise, Object is the default upper bound. The upper bound of a type parameter is specified in the type parameter section. To indicate the upper bound, follow the type parameter's name with the keyword extends and the class or interface name that represents the upper bound. In method maximum's type parameter section (Fig. 18.5), we specified the upper bound as type Comparable< T >. Thus, only Comparable< T > objects can be passed as arguments to maximumanything that is not Comparable< T > will result in compilation errors. Figure 18.6 simulates the erasure of method maximum's types by showing the method's source code after the type parameter section is removed and type parameter T is replaced with the upper bound, Comparable, throughout the method declaration. Note that the erasure of Comparable< T > is simply Comparable.

Figure 18.6. Generic method maximum after erasure is performed by the compiler.

 1 public static Comparable maximum(Comparable x, Comparable y, Comparable z)
 2 {
 3 Comparable max = x; // assume x is initially the largest
 4
 5 if ( y.compareTo( max ) > 0 )
 6 max = y; // y is the largest so far
 7
 8 if ( z.compareTo( max ) > 0 )
 9 max = z; // z is the largest
10
11 return max; // returns the largest object
12 } // end method maximum

After erasure, the compiled version of method maximum specifies that it returns type Comparable. However, the calling method does not expect to receive a Comparable. Rather, the caller expects to receive an object of the same type that was passed to maximum an argumentInteger, Double or String in this example. When the compiler replaces the type parameter information with the upper bound type in the method declaration, it also inserts explicit cast operations in front of each method call to ensure that the returned value is of the type expected by the caller. Thus, the call to maximum in line 23 (Fig. 18.5) is preceded by an Integer cast, as in

 (Integer) maximum( 3, 4, 5 )

the call to maximum in line 25 is preceded by a Double cast, as in

 (Double) maximum( 6.6, 8.8, 7.7 )

and the call to maximum in line 27 is preceded by a String cast, as in

 (String) maximum( "pear", "apple", "orange" )

In each case, the type of the cast for the return value is inferred from the types of the method arguments in the particular method call because, according to the method declaration, the return type and the argument types match. Note that you cannot use a method that accepts Objects because class Object provides only an equality comparison. Also note that without generics, programmers are responsible for the casting operation.

Introduction to Computers, the Internet and the World Wide Web

Introduction to Java Applications

Introduction to Classes and Objects

Control Statements: Part I

Control Statements: Part 2

Methods: A Deeper Look

Arrays

Classes and Objects: A Deeper Look

Object-Oriented Programming: Inheritance

Object-Oriented Programming: Polymorphism

GUI Components: Part 1

Graphics and Java 2D™

Exception Handling

Files and Streams

Recursion

Searching and Sorting

Data Structures

Generics

Collections

Introduction to Java Applets

Multimedia: Applets and Applications

GUI Components: Part 2

Multithreading

Networking

Accessing Databases with JDBC

Servlets

JavaServer Pages (JSP)

Formatted Output

Strings, Characters and Regular Expressions

Appendix A. Operator Precedence Chart

Appendix B. ASCII Character Set

Appendix C. Keywords and Reserved Words

Appendix D. Primitive Types

Appendix E. (On CD) Number Systems

Appendix F. (On CD) Unicode®

Appendix G. Using the Java API Documentation

Appendix H. (On CD) Creating Documentation with javadoc

Appendix I. (On CD) Bit Manipulation

Appendix J. (On CD) ATM Case Study Code

Appendix K. (On CD) Labeled break and continue Statements

Appendix L. (On CD) UML 2: Additional Diagram Types

Appendix M. (On CD) Design Patterns

Appendix N. Using the Debugger

Inside Back Cover



Java(c) How to Program
Java How to Program (6th Edition) (How to Program (Deitel))
ISBN: 0131483986
EAN: 2147483647
Year: 2003
Pages: 615

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net