Bill Venners writes about this in JavaWorld. The key criteria to consider is whether the relationship is really an “is-a” relationship, and just how strong the is-a is.
Make sure inheritance models the is-a relationship [...]
An important question to ask yourself when you think you have an is-a relationship is whether that is-a relationship will be constant throughout the lifetime of the application and, with luck, the lifecycle of the code. For example, you might think that an Employee is-a Person, when really Employee represents a role that a Person plays part of the time. What if the person becomes unemployed? What if the person is both an Employee and a Supervisor? Such impermanent is-a relationships should usually be modeled with composition.
He continues to point out that both code-reuse and polymorphism can be achieved with composition, and should not be a reason to use inheritance without a strong is-a relationship.
java.net hosts a discussion on the topic. A common approach is to code using interfaces, and use concrete inheritance in the implementations--in other words, use composition (with interfaces) in your design, use inheritance (for re-use or polymorphism) in the implementation. The is-a rule would still apply to the implementations, of course.