My last column introduced you to object orientation and discussed how some of the principles are expressed in Java. In particular, we were working with a chess example. Also, there was an assignment. You were to think about the classes: mammal, human and canine, and how one might use Java notation and inheritance to describe this small taxonomy system. This column will continue with OO by reviewing the assignment and explain a powerful feature called polymorphism.
Remember that the principal thrust of OO is to model a system. A system is composed of objects and the relationships and interactions between the objects. An object is a structure that exhibits state, identity and behavior. We create a class to describe a definition for a type of object. A class is similar to a blueprint for a house object. It describes the structure of a house, but different houses built from the same blueprint can have different colors, appliances, etc. Instances of classes are created that can actually maintain states and do things (behave).
The assignment, discussed previously, was to consider a taxonomy system. A Mammal would be a base class that defines some common behaviors of mammals, and classes canine and human would implement the behaviors particular to their own species. The goal is to model this system, identifying the objects and their states, identities and behaviors. To start modeling the system, consider the base class mammal. What is a mammal? If I remember correctly from elementary school, a mammal is a warm blooded creature that has fur and gives birth to live young. There is probably more to it, but this definition will suffice.
Considering this, what are some possible states of a mammal? The ones mentioned in the definition are fixed. All mammals have fur, warm blood and give birth to live young. What are some states that can vary among mammals? Well, mammals are either male or female. Mammals have a specific number of legs. And of course, a mammal can be a herbivore, carnivore or omnivore.
What are the identities of a mammal? What else is a mammal besides just being a mammal? We can say that a mammal is also a vertebrae. Just as a human is a mammal, a mammal is a vertebrae. Generally, if you can describe the relationship between two classes using the phrase is a' or is a kind of', the two classes share an inheritance relationship. In Java, one would denote that class Mammal extends Vertebrae, and class Human extends Mammal. The relationship is transitive, meaning that a Human is also (is a') Vertebrae.
What are the behaviors of a mammal? There are many things that a mammal can do, but for this exercise, the mammal model will have only one behavior: walk. All mammals can walk (we assume). Take a look at Listing 1 to see how our mammal is modeled in Java.
Notice the static final state variables. These are constant values that are included in the class to assist the programmer. Since things like gender and dietHabits can only have certain values, it is common practice to include static final data members to ease the assignment of these states. Later in some other part of our code, a programmer can use these static final data members by making assignments such as: gender = Mammal.MALE; or dietHabits = Mammal.OMNIVORE.
The next step is to model a Human. As with Mammal, we are going to keep the model simple to illustrate a point. We can say that a human is a mammal with some added states and behaviors. What other states can a human maintain? In the interest of simplicity, let's say that a human has a name. Also in the interest of simplicity, let's say that the only other behavior that separates a human from a mammal is a human's ability to go to work. The model for this definition of a human would look like Listing 2.
Notice first that a Human is not an abstract class. We have designed our system this way to better reflect the real world. There is nothing in the real world that you can point to and say: "That is ONLY a mammal." Every mammal is a member of some species. So, since there are no real world objects that are only mammals, there will be no objects in our system that are only mammals. You cannot create a mammal object.
Keep in mind that just as in the real world, you can point to a human or dog and say, "That is a Mammal." In our system too, you can refer to an instance of Human or Canine and say, "That is a Mammal." However, in addition to being a mammal, those objects can also be identified as Humans and Canines. We will examine this in more detail after we model class Canine.
Class Human extends Mammal. Remember from the last article that the first line of a Java class definition expresses the identities of the class. A Human can be identified as a Human or as a Mammal. What does it mean to be a mammal? In our definition (i.e. our Mammal class), a Mammal has certain states (i.e. gender, dietHabits, etc.) and behaviors. These states and behaviors are inherited by class Human. This means that every human also has a gender and dietHabits and can also Walk. Furthermore, class Mammal extends class Vertebrae, which we have not defined. Had class Vertebrae been defined, a Human would have the behaviors and states defined in that class as well as a Vertebrae identity.
Class Human provides a class specific implementation for the abstract method Walk(). This means that we define the walk method for a human to reflect how a human walks. First of all, a human has two legs. He will throw one foot out in front of him, fall a bit until that foot hits the ground, and then repeat the process for the other foot. The Walk method for a human will be different than the walk method for a four legged creature because a four legged creature walks differently. Focus on the fact that all mammals can walk, regardless of how the method is actually implemented.
Finally, class Human defines the state variable name and the behavior goToWork(). These are things specific to Humans. Since these states and behaviors are ones not shared by all mammals, they are defined in the human class.
A Canine is also a Mammal. For this exercise, our Canine class will have a bark behavior, and they will be carnivores. Look at Listing 3 for a brief class description.
We now have classes that we can use to create Mammal, Canine and Human objects. Our class definitions are pretty light, but sufficient to demonstrate polymorphism. Polymorphism is an ability to have many shapes. It refers to the ability of an object to assume the identity of one of its parent classes. In this exercise, an object of type human can assume the identity of a Mammal. In other words, a variable of type Mammal can contain an instance of a Human or a Canine or any other descendant of Mammal. Listing 4 demonstrates this.
When a Human is being identified as a Mammal, only methods defined in class Mammal can be called. m.bark() makes no sense because bark() is a behavior of a Canine. When walk() is called on m from Listing 4, the walk method defined in class Human is actually invoked. Similarly, a state variable overridden in class Human will be accessed through m with the same effect. That is, even though we are identifying the object through m (a mammal), the state variable accessed will actually be of class Human. This leads to a more formal definition of polymorphism: Polymorphism is an object's inherent ability to be identified as one of its parent classes, yet implement its own specific states and behaviors.
Notice that polymorphism is an inherent ability'. Inheritance and polymorphism are intrinsically linked. You can't have polymorphism without inheritance. The key here is that a class can have many identities. Remember, the first line of a class definition enumerates the possible identities that the class can assume. In the case of Human and Canine, both can also be identified as Mammals. Even when an object of type Human or Canine is identified as an object of type Mammal, the implementation of methods and data contained in state variables remains. Therefore, if m.walk() is called immediately after m = john in Listing 4, the walk() method executed will be john's walk method. The Human one.
Polymorphism is widely demonstrated in Java, especially in the AWT. The Abstract Windowing Toolkit has an abstract base class Component. Component is the parent class of all of Java's widgets. Things like Buttons, Labels and Textfields all extend class Component. A Panel is an object that can contain other Components. One might add Buttons and other Components to a Panel for screen display. A Panel needs to know the size of every widget that it is holding to make sure that everything is laid out correctly. Thanks to polymorphism, a Panel can maintain an internal list or array of Components. Any descendant of Component can be added to the list, and therefore be displayed on a Panel. So, using one array of type Component, a Panel can keep a list of any kind of widget added to it, as long as the widget descends class Component. Furthermore, method getSize() is defined in class Component. The panel can traverse the array and call getSize() on every element. Polymorphism will ensure that the actual size returned, is the size stored in the Button, Label, Textfield or whatever the actual Component is that has been added to the Panel.
There are many more examples of Polymorphism in the Java core packages. Your assignment is to look through the API documentation and find some. Start with any package you like. You will find a lot in the java.io package. Remember, polymorphism is an object's inherent ability to be identified as one of its parent classes, yet implement its own specific states and behaviors. Look for abstract base classes. They are typically a dead giveaway for polymorphism.
About the Author
John V. Tabbone is a lecturer at New York
University's Information Technologies Institute, where he teaches two Java programming courses and advises on curriculum development. He has been a
professional Java programmer since early 1996, and continues to consult on and develop systems for a variety of New York based businesses. You may
e-mail him with questions and comments at
Listing 1: Abstract class Mammal extends Vertebrae.
public static final int MALE = 0;
public static final int FEMALE = 1;
public static final int HERBIVORE = 0;
public static final int CARNIVORE = 1;
public static final int OMNIVORE = 2;
public final boolean hasWarmBlood = true;
public final boolean givesBirthToLiveYoung = true;
public final boolean hasFur = true;
public int gender; // 0 for male, 1 for female
public int numLegs; //
public int dietHabits; // 0 for herbivore, 1 for carnivore, 2 for
abstract public void walk();
} // end class
Listing 2: Class Human extends Mammal.
gender = MALE;
numLegs = 2;
dietHabits = OMNIVORE;
public void walk()
// The code that describes how a human walks goes here.
public void goToWork()
// The code that describes how a human goes to work goes here.
} // end class
Listing 3: Class Canine extends Mammal.
gender = MALE;
numLegs = 4
dietHabits = CARNIVORE;
public void walk()
// the code that describes how a human walks goes here
public void bark()
Human john = new Human(); // create a human object
Mammal m; // declare a Mammal variable
m = john; // this is legal;