3.1 OOP: Class Hierarchy

In object-oriented programming, a class is a template that defines the state and behavior common to objects of a certain kind. A class can be defined in terms of other classes. For example, a truck and a racing car are both examples of a car. Another example is a letter and a digit being both a single character that can be drawn on the screen. In the latter example, the following terminology is used:

The third formulation expresses that a subclass inherits state (instance variables) and behavior (methods) from its superclass(es). Letters and digits share the state (name, font, size, position) and behavior (draw, resize, ...) defined for single characters.

The purpose of a subclass is to extend existing state and behavior: a letter has a case (upper and lower case, say stored in the instance variable letterCase) and methods for changing the case (toUpperCase, toLowerCase) in addition to the state that it already has as a character.

However, a digit does not have a case, so the methods toUpperCase, toLowerCase do not belong on the common level of the Character class. There are methods that are special to the digit class. For instance, a digit may be constructed from an integer value between 0 and 9, and conversely, the integer value of a digit may be the result of say the intValue method.

Subclasses can also override inherited behavior: if you had a colored character as subclass of the character class, you would override the definition of the draw method of the character class so that color is taken into account when drawing the character on the screen. This leads to what is called in OOP jargon polymorphism: the same message sent to different objects results in behavior that is dependent on the nature of the object receiving the message.

In graphical terms, the above character example may look as follows:

You are not limited to just one layer of inheritance: for example, the letter class can have on its turn the subclasses vowel and consonant.

The classes form a class hierarchy, or inheritance tree, which can be as deep as needed. The hierarchy of classes in Java has one root class, called Object, which is superclass of any class. Instance variable and methods are inherited down through the levels. In general, the further down in the hierarchy a class appears, the more specialized its behavior. When a message is sent to an object, it is passed up the inheritance tree starting from the class of the receiving object until a definition is found for the method. This process is called upcasting. For instance, the method toString() is defined in the Object class. So every class automatically has this method. If you want that your particular toString() method looks differently, you can reimplement it in your class. In this way you can override a method in a given class by redefining it in a subclass.

In graphical terms, the inheritance tree and the message handling may look as follows:

The picture showing the overriding of methods, may look as follows: