Suppose that you want a version of Box that only accepts numbersand further, that based on that, you want to add some functionality that's specific to numbers. To accomplish this, you need to restrict the types that are allowed.
This is pretty simpleyou can actually insert an extends className onto your type variable, and voila! Check out Example 2-3.
package com.oreilly.tiger.ch02; import java.util.Iterator; public class NumberBox<N extends Number> extends Box<N> { public NumberBox( ) { super( ); } // Sum everything in the box public double sum( ) { double total = 0; for (Iterator<N> i = contents.iterator( ); i.hasNext( ); ) { total = total + i.next( ).doubleValue( ); } return total; } }
The only types allowed here are extensions of the class Number (or Number itself). So the following statement is illegal:
NumberBox<String> illegal = new NumberBox<String>( );
The compiler indicates that the bound of this type is not met. The bound, of course, is the restriction put upon typing, and that's exactly what the error message indicates:
[javac] code\src\com\oreilly\tiger\ch02\GenericsTester.java:118: type parameter java.lang.String is not within its bound [javac] NumberBox<String> illegal = new NumberBox<String>( ); [javac] ^ [javac] code\src\com\oreilly\tiger\ch02\GenericsTester.java:118: type parameter java.lang.String is not within its bound [javac] NumberBox<String> illegal = new NumberBox<String>( ); [javac] ^
You can use this same syntax in method definitions:
public static double sum(Box<? extends Number> box1, Box<? extends Number> box2) { double total = 0; for (Iterator<? extends Number> i = box1.contents.iterator( ); i.hasNext( ); ) { total = total + i.next( ).doubleValue( ); } for (Iterator<? extends Number> i = box2.contents.iterator( ); i.hasNext( ); ) { total = total + i.next( ).doubleValue( ); } return total; }
This starts to get a little weird, I realize, but them's the breaks. It gets worse because you have to use the wildcard indicator, and then repeat the expression (? extends Number) in the method body. One way to clean this up is to declare your own type variable inline (and make your syntax even odder):
public static <A extends Number> double sum(Box<A> box1, Box<A> box2) { double total = 0; for (Iterator<A> i = box1.contents.iterator( ); i.hasNext( ); ) { total = total + i.next( ).doubleValue( ); } for (Iterator<A> i = box2.contents.iterator( ); i.hasNext( ); ) { total = total + i.next( ).doubleValue( ); } return total; }
The portion of the method declaration right before the return value, <A extends Number>, provides a typing variable which is then used throughout the method declaration and body.
NOTE
You can also check out the in-depth chapter on generics in Java in a Nutshell, Fifth Edition (O'Reilly).
...the other thousand-and-one variations on this theme? I say that only somewhat tongue-in-cheek, to stress that generics are a huge topic unto themselves. In fact, I suspect that there will be at least a few books entirely on generics alone before 2004 has come to a close, and those books will cover far more than this chapter. It's worth knowing that there are ways to extend classes and implement interfaces in your type variables, there are ways to require the superclass of a particular object, and a whole lot more.
Of course, there are ways to juggle knives also, but some things just don't fit into a developer's notebook. You should have more than enough tools to get most of your programming tasks done, and by the time you've got all this mastered, those other books will probably be on bookshelves. So enjoy this, take a deep breath, and turn the page for more Tiger antics.