Consider composition as an alternative to subclassing.
Composition:
- is implemented simply by forwarding all calls to an object field
- has no dependence on implementation details of the object field
- is more flexible, since it's defined dynamically at run-time, not statically at compile-time
- it violates encapsulation, since the implementations of the superclass and subclass become tightly coupled
- new methods added to the superclass can break the subclass
- superclass and subclass need to evolve in parallel
- designing a class so that it may be safely extended takes extra work - extending a class not explicitly designed for such use is risky
- different packages are often under the control of different programmers - extending a class in a different package is risky
- Serializable and Cloneable are more difficult to implement when inheritance is present
- given a concrete class Aircraft which implements Comparable and overrides equals, it's not possible to extend such a class (Boeing747) and add a new significant field (fUpperDeck), and simultaneously provide completely correct implementations of compareTo and equals. In this situation, composition is required. (See Effective Java for further discussion.)
A common exception is the template method design pattern. There, the safest style is to make all items in the abstract base class final, except for the single abstract method which needs to be implemented by the subclass.
An interesting quote from chapter one of Design Patterns:
"That leads us to our second principle of object-oriented design:
Favor object composition over class inheritance.
...Nevertheless, our experience is that designers overuse inheritance as a reuse technique, and designs are often made more reusable (and simpler) by depending more on object composition. You'll see object composition applied again and again in the design patterns."
(Their first principle, stated earlier in the chapter, is "Program
to an interface, not an implementation".)