Another variation of this problem arises when you try to write an equals method. Object defines equals with the following signature:

public boolean equals(Object object)

Rather than implementing a strongly-typed version of this, it's often good practice to correctly implement this signature, because you cannot guarantee that the caller knows the type of the object it is passing to equals. If the caller doesn't know the type of the object it is passing in, then it might call the equals method with the signature equals(Object object), and you might wind up with a incorrect negative return value. So most programmers end up writing something like the following:

public boolean equals(Object object) {
// if the other instance doesn't have the same class,
// they're not equal
if (object.getClass() != this.getClass()) {
return false;
}
// okay. it's the same class. let's cast it and
// *really* check for equality.
}
}

But this way of thinking can cause problems. Consider the following class:

In this admittedly contrived example, we have the Athlete class defined as a generic class with a single type variable named T. And the equals method has a certain face validity, until you realize that getClass returns Athlete, not Athlete<Football> or Athelete<Baseball>.
As it stands, this code would claim that the football player Will Allen (number 25 on the Giants) is the same as the baseball player Barry Bonds (number 25 on the Giants). Intuitively, I expect this problem to be eliminated by the first if, which checks the classes.

The moral of the story is: be careful (or be prepared to defend the claim that Will Allen is the best slugger since Babe Ruth). In this case, I'd probably define FootballPlayer and BaseballPlayer to be explicit subclasses of Athlete

Generics and Inheritance

Another interesting question revolves around how generics works with inheritance.
Recall that, in part 2 of this series, we had a whole hierarchy of command objects. In particular, we had an abstract base class, AbstractRemoteMethodCall; an abstract subclass, ServerDescriptionBasedRemoteMethodCall; and a concrete subclass TranslateWord.

In general, subclasses rarely add new type variables. Type variables represent extra flexibility in how a class can be used, and abstract superclasses are "more generic" than concrete subclasses. Put more concretely, by the time we get around to writing a very specific class like TranslateWord, any flexibility as to what the argument or return value types can be ought to be gone. This is summarized in the following UML diagram:

The relationship between inheritance and genericity in our command object framework. Generally speaking, subclasses are more constrained (and less generic) than superclasses.

In particular, we're going to make AbstractRemoteMethodCall's makeCall method generic, so that both the return value and the exceptions thrown from makeCall can be strongly typed. Here's what the class and method declarations will look like for all three classes.

Note what we did. When we defined ServerDescriptionBasedRemoteMethodCall<T, E >, we simply declared it to extend AbstractRemoteMethodCall<T, E>. This means that when the parametrized types for an instance of ServerDescription are specified, they will be used by the code for AbstractRemoteMethodCall.

There's a very important catch here -- this relies on the order of the type variables, and not their names. The following code, which switches the order of arguments and sets the superclasses' T type variable to the value of the subclass's W type variable, is perfectly valid (if somewhat confusing):

The other way to deal with generic types within inheritance is to simply specify the concrete types directly, as part of the subclass declaration. We did this with TranslateWord, when we wrote extends ServerDescriptionBasedRemoteMethodCall<Word, CouldNotTranslateException>. This line of code automatically tells the compiler "Whenever someone creates an instance of TranslateWord, T is mapped to Word and E is mapped to Exception."

This is all pretty straightforward; the important point to note is that you can't deal with the problem dynamically, or at runtime. Code like the following, which attempts to set the type variable from within a constructor, just won't work:

When you think about it, this is reasonable -- the whole goal of the generics specification is to enable the compiler to check types at compile-time.

Generics and Exceptions

The last remaining topic I'm going to cover in this whirlwind tour of JSR-014 is how to use generic exceptions. By now, you should have some intuition about how they're going to work: the class definition will include a parametrized type for an exception and the method definition will simply declare that it throws the type variable. In fact, we surreptitiously did exactly that in the previous section. Here's the example code:

In this code snippet, AbstractRemoteMethodCall is declared to take two type variables, T and E. T is used as the return value on makeCall and E is used for exceptions.
This works, and makes the code a little bit more typesafe (recall that, previously, makeCall was declared to throw Exception).

To be honest, though, I'm a little disappointed in the way exceptions are handled. The basic problem is this: while you can throw generic exceptions, you can't specify a different number of exceptions in the subclass. I'd love to have some notion of variable length generic types for exceptions so that something like the following code would mean "where the superclass claims to throw E, the subclass wants the compiler to interpret E as being one of these four types (all of which must be caught over on the client side)":

As matters stand, the subclass must declare that it throws some common superclass of A, B, C, and D. But that's a minor quibble. The ability to narrow exceptions in frameworks and libraries is extraordinarily useful. To see why, consider a method that, because it will be implemented by a variety of subclasses, is declared as throwing Exception. For example,

public T performComputation(W argument) throws Exception {

The problem with this is that the code inside performComputation isn't forced to catch any exceptions. It doesn't even have to catch the exceptions that are local problems (e.g. exceptions that the superclass doesn't know how to handle or correct).

Suppose, for example, one implementation of performComputation contained some JDBC calls. Ordinarily, JDBC code has to be wrapped in a try/catch block to catch instances of SQLException. SQLException is a checked exception and the compiler will make sure that it, or a superclass, is caught somewhere in the stack frame. Which means that if performComputation wasn't declared as throwing Exception, the method wouldn't even compile until the possibility of an SQLException was explicitly addressed.

But since performComputation is declared to throw Exception, the compiler won't complain about SQLException. Instead, when an instance of SQLException is thrown, will be propagated up the stack, to eventually be caught someplace else.

On the other hand, consider the following declaration:

public T performComputation(W argument) throws E {

In this method, any exceptions that don't extend E must still be checked locally. This means that the compiler will force you to deal with some exceptional conditions locally, which is what you probably want. In the case of JDBC calls, as long as E isn't a superclass of SQLException, the implementation of until performComputation will have to address the possibility of an SQLException.

Note:. This leads to an important design tip -- always use a separate exception hierarchy for exceptions in your program. If you throw generic exceptions, or overload ones that are defined by frameworks you happen to be using, you're working against the compiler.

If you've read this far, and especially if you read the previous section, you're probably thinking something like "Ouch! My head feels like it's been put through a meat-grinder! What is the point of all this stuff?" Well, remember the goal of the generics specification I stated a few pages back:

By using generics, a programmer can convert casting errors from run-time exceptions to compiler errors. This results in fewer programming errors and better code.

In this section, we're going to systematically convert the command objects framework into code that uses generics. The first class we're going to convert is RemoteStubCache.

Recall that RemoteStubCache is a local cache of stubs used by an RMI client. Unless stubs are cached locally, an RMI client has to make two remote method calls for every "logical remote call": one remote call to a naming service and one remote call to the actual remote server. Converting RemoteStubCache is pretty easy: the only thing that must be changed is the internal use of Hashtable. In fact, only two lines of code changed. Here's the new version of RemoteStubCache:

public class RemoteStubCache
{
// this next declaration used to be
// private static Hashtable _serverDescriptionsToStubs...

AbstractRemoteMethodCall is trickier. We're going to add two type variables. The first type variable will be used for the value returned from from makeCall and the second will restrict the range of allowable exceptions. Here's the code:

The result of this is that code in ClientFrame that uses the TranslateWord command object to perform a remote method invocation doesn't need to cast the return value from makeCall. Here's the new code:

TranslateWord translateMethod = new TranslateWord(translatorServerDescription, word, targetLanguage);
try {
// no cast in next line
Word result = translateMethod.makeCall();