CHAPTER 6 ■ OBJECT-ORIENTED PROGRAMMING
However, Java does provide a way to get most of the benefits and very few of the problems from
multiple inheritance. You can include instances of other classes as fields within your class. That way,
your class can access the public (or package, if your class is in the same package) fields and methods
within those classes. Because you can't access the private bits and because you can't include abstract
classes, you're (if those other classes are well designed) well protected from getting into problems that
arise from having more than one ancestor. This technique is sometimes called composition, because
your new class is composed, in part, of the publicly available bits of other classes. As with all techniques,
be sure you need to do it, though. The simpler and cleaner you keep your objects, the easier it is to get
your program to work, and the more your fellow developers appreciate your work.
Here's an example of the kind of problem for which composition works really well (with thanks to
Jeremy Conner at Uplogix for the idea). Consider a classic monster from horror movies: a wolfman.
Typically, a wolfman is more man than wolf (if only because the actors in the furry suits are themselves
humans and not wolves). Consequently, we might model our wolfman by making a new class called
Wolfman that extends Man (which might itself extend Human and be parallel to Woman) and includes an
instance of the Wolf class as one of its fields. Then we can get all the attributes of a man and most of the
attributes (anything declared public) from a wolf and have a software model of a wolfman.
Modeling Behavior through Interfaces
Java includes the concept of interfaces. An interface is a set of methods (basically, things an object can
do) that an object must have if it uses (the keyword in Java is implements) that interface. In particular, a
class that implements an interface must implement all the methods within that interface. Let's return to
our three concrete classes: Cat, Dog, and Mouse.
Cats are predators and carnivores. Dogs are carnivores (there's some argument that they're
omnivores, but we call them carnivores for the sake of our example) and both predators and scavengers.
Mice are herbivores and are not predators or scavengers. So, we might create a set of interfaces to model
the behavior of the animals we chose. We have the following interfaces: Predator, Scavenger, Carnivore,
and Herbivore. If we add bears, we need an Omnivore interface, too.
Abstract Classes
Sometimes, a Java developer writes a class that should never be instantiated. That is, it's a class that will
never have an object associated with it. Such a class usually serves as the basis for other classes. Our
Mammal class is an example of such a class. All the mammals in the real world are specific types of
mammals rather than just mammals. Cats, dogs, mice, humans, whales, and so on are all mammals, of
course, but they all have more specific names and more specific traits. So, there's no actual animal that's
a generic mammal. Consequently, we don't want anyone to create an instance of our Mammal class,
because that would be bad modeling.
Java lets developers declare that a class should never have an instance by using the abstract
keyword. In Java, abstract means that the class can still be extended by other classes but that it can
never be instantiated (turned into an object). Returning to our example, we can have Mammal be abstract
(because there's no such thing as a generic mammal) and still have Cat, Dog, and Mouse extend Mammal
(because cats, dogs, and mice are mammals).
The hard part is figuring out when a class should be abstract. Modeling the animal kingdom is a
simple example, so it's not hard to see that Mammal should be an abstract class.
The opposite of an abstract class is usually called a concrete class. Concrete classes are the default,
so there's no keyword for it. In most programs, most classes are concrete classes.