Generics and Relationships in Java - Writing Generic Classes
(Page 5 of 5 )
Here, we have created a nongeneric subclass, DateList, of the concrete generic instantiation ArrayList<Date>. The DateList is a type of ArrayList<Date> and inherits the particular instantiation of all of the methods, just as it would from any other parent. We can even assign it back to the parent type if we wish, as shown in this example.
A generic subtype of a generic class may extend either a concrete instantiation of the class, as in the previous example, or it may share a type variable that it "passes up" to the parent upon instantiation:
class AdjustableTrap< T > extends
Trap< T > {
public void setSize( int i ) { ... }
}
Here, the type variable T used to instantiate the AdjustableTrap class is passed along to instantiate the base class, Trap. When the user instantiates the AdjustableTrap on a particular parameter type, the parent class is instantiated on that type as well.
Exceptions and Generics
Types appear in the body of classes in another place--the throws clauses of methods. Type variables may be used to define the type of exceptions thrown by methods, but to do so we need to introduce the concept of bounds. We cover bounds more in the next section, but in this case, the usage is really simple. We just need to ensure that the type variable we want to use as our exception type is actually a type of Throwable. We can do that by adding an extends clause to the declaration of our type variable, like this:
< T extends Throwable >
Here is an example class, parameterized on a type that must be a kind of Throwable. It's test() method accepts an instance of that kind of object and throws it as a checked exception:
ExceptionTester< T extends Throwable > {
public void test( T exception ) throws T { throw exception; }
}
try {
new E<ClassNotFoundException>().test(
new ClassNotFoundException() );
} catch ( ClassNotFoundException e ) { ... }
The addition of the bound imposes the restriction that the parameter type used to instantiate the class, T, must be a type of Throwable. And we referenced the type T in the throws clause. So, an ExceptionTester<ClassNotFoundException> can throw a ClassNotFoundException from its test() method. Note that this is a checked exception and that has not been lost on the compiler. The compiler enforces the checked exception type that it just applied.
No generic Throwables
We saw that a type variable can be used to specify the type of Throwable in the throws clause of a method. Perhaps ironically, however, we cannot use generics to create new types of exceptions. No generic subtypes of Throwable are allowed. If you think about this for a moment, you'll see that to be useful, generic Throwables would require try/catch blocks that can differentiate instantiations of Throwable. And since (once again) there is no runtime representation of generics, this isn't possible with erasure.
Please check back next week for the continuation of this article.
| DISCLAIMER: The content provided in this article is not warranted or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real-world tactics for security and implementation of best practices. We are not liable for any negative consequences that may result from implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware. |
|
This article was excerpted from chapter eight of the book Learning Java, third edition, written by Patrick Niemeyer and Jonathan Knudsen (O'Reilly; ISBN: 0596008732). Check it out today at your favorite bookstore. Buy this book now.
|
|