> ### Section 5.4
> Inheritance, Polymorphism, and Abstract Classes

> A CLASS REPRESENTS A SET OF OBJECTS which share the same structure and behaviors. The class determines the structure of objects by specifying variables that are contained in each instance of the class, and it determines behavior by providing the instance methods that express the behavior of the objects. This is a powerful idea. However, something like this can be done in most programming languages. The central new idea in object-oriented programming -- the idea that really distinguishes it from traditional programming -- is to allow classes to express the similarities among objects that share some, but not all, of their structure and behavior. Such similarities can expressed using inheritance and polymorphism.

> The topics covered in this section are relatively advanced aspects of object-oriented programming. Any programmer should know what is meant by subclass, inheritance, and polymorphism. However, it will probably be a while before you actually do anything with inheritance except for extending classes that already exist.

> The term inheritance refers to the fact that one class can inherit part or all of its structure and behavior from another class. The class that does the inheriting is said to be a subclass of the class from which it inherits. If class B is a subclass of class A, we also say that class A is a superclass of class B. (Sometimes the terms derived class and base class are used instead of subclass and superclass.) A subclass can add to the structure and behavior that it inherits. It can also replace or modify inherited behavior (though not inherited structure). The relationship between subclass and superclass is sometimes shown by a diagram in which the subclass is shown below, and connected to, its superclass.

> In Java, when you create a new class, you can declare that it is a subclass of an existing class. If you are defining a class named "B" and you want it to be a subclass of a class named "A", you would write

>             class B extends A {
>                 .
>                 .  // additions to, and modifications of,
>                 .  // stuff inherited from class A
>                 .
>             }

> Several classes can be declared as subclasses of the same superclass. The subclasses, which might be referred to as "sibling classes," share some structures and behaviors -- namely, the ones they inherit from their common superclass. The superclass expresses these shared structures and behaviors. In the diagram to the left, classes B, C, and D are sibling classes. Inheritance can also extend over several "generations" of classes. This is shown in the diagram, where class E is a subclass of class D which is itself a subclass of class A. In this case, class E is considered to be a subclass of class A, even though it is not a direct subclass.

> Let's look at an example. Suppose that a program has to deal with motor vehicles, including cars, trucks, and motorcycles. (This might be a program used by a Department of Motor Vehicles to keep track of registrations.) The program could use a class named `Vehicle` to represent all types of vehicles. The `Vehicle` class could include instance variables such as `registrationNumber` and `owner` and instance methods such as `transferOwnership()`. These are variables and methods common to all vehicles. Three subclasses of `Vehicle` -- `Car`, `Truck`, and `Motorcycle` -- could then be used to hold variables and methods specific to particular types of vehicles. The `Car` class might add an instance variable `numberOfDoors`, the `Truck` class might have `numberOfAxels`, and the `Motorcycle` class could have a boolean variable `hasSidecar`. (Well, it could in theory at least, even if it might give a chuckle to the people at the Department of Motor Vehicles.) The declarations of these classes in Java program would look, in outline, like this:

>          class Vehicle {
>             int registrationNumber;
>             Person owner;  // (assuming that a Person class has been defined)
>             void transferOwnership(Person newOwner) {
>                 . . .
>             }
>             . . .
>          }
>          class Car extends Vehicle {
>             int numberOfDoors;
>             . . .
>          }
>          class Truck extends Vehicle {
>             int numberOfAxels;
>             . . .
>          }
>          class Motorcycle extends Vehicle {
>             boolean hasSidecar;
>             . . .
>          }

> Suppose that `myCar` is a variable of type `Car` that has been declared and initialized with the statement

> `Car myCar = new Car();`

> (Note that, as with any variable, it is OK to declare a variable and initialize it in a single statement. This is equivalent to the declaration "`Car myCar`;" followed by the assignment statement "`myCar = new Car();`".) Given this declaration, a program could to refer to `myCar.numberOfDoors`, since `numberOfDoors` is an instance variable in the class `Car`. But since class `Car` extends class `Vehicle`, a car also has all the structure and behavior of a vehicle. This means that `myCar.registrationNumber`, `myCar.owner`, and `myCar.transferOwnership()` also exist.

> Now, in the real world, cars, trucks, and motorcycles are in fact vehicles. The same is true in a program. That is, an object of type `Car` or `Truck` or `Motorcycle` is automatically an object of type `Vehicle`. This brings us to the following Important Fact:

> A variable that can hold a reference
> to an object of class A can also hold a reference
> to an object belonging to any subclass of A.

> The practical effect of this in our example is that an object of type `Car` can be assigned to a variable of type `Vehicle`. That is, it would be legal to say

> `Vehicle myVehicle = myCar;`

> or even

> `Vehicle myVehicle = new Car();`

> After either of these statements, the variable `myVehicle` holds a reference to a `Vehicle` object that happens to be an instance of the subclass, `Car`. The object "remembers" that it is in fact a `Car`, and not just a `Vehicle`. Information about the actual class of an object is stored as part of that object. It is even possible to test whether a given object belongs to a given class, using the `instanceof` operator. The test:

> `if (myVehicle instanceof Car) ...`

> determines whether the object referred to by `myVehicle` is in fact a car.

> On the other hand, if `myVehicle` is a variable of type `Vehicle` the assignment statement

> `myCar = myVehicle;`

> would be illegal because `myVehicle` could potentially refer to other types of vehicles that are not cars. This is similar to a problem we saw previously in Section 2.5: The computer will not allow you to assign an `int` value to a variable of type `short`, because not every `int` is a `short`. Similarly, it will not allow you to assign a value of type `Vehicle` to a variable of type `Car` because not every vehicle is a car. As in the case of `ints` and `shorts`, the solution here is to use type-casting. If, for some reason, you happen to know that `myVehicle` does in fact refer to a `Car`, you can use the type cast `(Car)myVehicle` to tell the computer to treat `myVehicle` as if it were actually of type `Car`. So, you could say

> `myCar = (Car)myVehicle;`

> and you could even refer to ((Car)myVehicle).numberOfDoors. As an example of how this could be used in a program, suppose that you want to print out relevant data about a vehicle. You could say:

>                System.out.println("Vehicle Data:");
>                System.out.println("Registration number:  "
>                                              + myVehicle.registrationNumber);
>                if (myVehicle instanceof Car) {
>                   System.out.println("Type of vehicle:  Car");
>                   Car c;
>                   c = (Car)myVehicle;
>                   System.out.println("Number of doors:  " + c.numberOfDoors);
>                }
>                else if (myVehicle instanceof Truck) {
>                   System.out.println("Type of vehicle:  Truck");
>                   Truck t;
>                   t = (Truck)myVehicle;
>                   System.out.println("Number of axels:  " + t.numberOfAxels);
>                }
>                else if (myVehicle instanceof Motorcycle) {
>                   System.out.println("Type of vehicle:  Motorcycle");
>                   Motorcycle m;
>                   m = (Motorcycle)myVehicle;
>                   System.out.println("Has a sidecar:    " + m.hasSidecar);
>                }

> Note that for object types, when the computer executes a program, it checks whether type-casts are valid. So, for example, if `myVehicle` refers to an object of type `Truck`, then the type cast `(Car)myVehicle` will produce an error.

> As another example, consider a program that deals with shapes drawn on the screen. Let's say that the shapes include rectangles, ovals, and roundrects of various colors.

> Three classes, `Rectangle`, `Oval`, and `RoundRect`, could be used to represent the three types of shapes. These three classes would have a common superclass, `Shape`, to represent features that all three shapes have in common. The `Shape` class could include instance variables to represent the color, position, and size of a shape. It could include instance methods for changing the color, position, and size of a shape. Changing the color, for example, might involve changing the value of an instance variable, and then redrawing the shape in its new color:

>            class Shape {

>                Color color;   // Color of the shape.  (Recall that class Color
>                               // is defined in package java.awt.  Assume
>                               // that this class has been imported.)

>                void setColor(Color newColor) {
>                      // Method to change the color of the shape.
>                   color = newColor; // change value of instance variable
>                   redraw(); // redraw shape, which will appear in new color
>                }

>                void redraw() {
>                      // method for drawing the shape
>                   ? ? ?  // what commands should go here?
>                }

>                . . .          // more instance variables and methods

>            } // end of class Shape

> Now, you might see a problem here with the method `redraw()`. The problem is that each different type of shape is drawn differently. The method `setColor()` can be called for any type of shape. How does the computer know which shape to draw when it executes the `redraw()`? Informally, we can answer the question like this: The computer executes `redraw()` by asking the shape to redraw itself. Every shape object knows what it has to do to redraw itself.

> In practice, this means that each of the specific shape classes has its own `redraw()` method:

>            class Rectangle extends Shape {
>               void redraw() {
>                  . . .  // commands for drawing a rectangle
>               }
>               . . . // possibly, more methods and variables
>            }
>            class Oval extends Shape {
>               void redraw() {
>                  . . .  // commands for drawing an oval
>               }
>               . . . // possibly, more methods and variables
>            }
>            class RoundRect extends Shape {
>               void redraw() {
>                  . . .  // commands for drawing a rounded rectangle
>               }
>               . . . // possibly, more methods and variables
>            }

> If `oneShape` is a variable of type `Shape`, it could refer to an object of any of the types, `Rectangle`, `Oval`, or `RoundRect`. As a program executes, and the value of `oneShape` changes, it could even refer to objects of different types at different times! Whenever the statement

> `oneShape.redraw();`

> is executed, the redraw method that is actually called is the one appropriate for the type of object to which `oneShape` actually refers. There may be no way of telling, from looking at the text of the program, what shape this statement will draw, since it depends on the value that `oneShape` happens to have when the program is executed. Even more is true. Suppose the statement is in a loop and gets executed many times. If the value of `oneShape` changes as the loop is executed, it is possible that the very same statement "`oneShape.redraw();`" will call different methods and draw different shapes as it is executed over and over. We say that the `redraw()` method is polymorphic. A method is polymorphic if the action performed by the method depends on the actual type of the object to which the method is applied. Polymorphism is one of the major distinguishing features of object-oriented programming.

> Perhaps this becomes more understandable if we change our terminology a bit: In object-oriented programming, calling a method is often referred to as sending a message to an object. The object responds to the message by executing the appropriate method. The statement "`oneShape.redraw();`" is a message to the object referred to by `oneShape`. Since that object knows what type of object it is, it knows how it should respond to the message. From this point of view, the computer always executes "`oneShape.redraw();`" in the same way: by sending a message. The response to the message depends, naturally, on who receives it. From this point of view, objects are active entities that send and receive messages, and polymorphism is a natural, even necessary, part of this view. Polymorphism just means that different objects can respond to the same message in different ways.

> One of the most beautiful things about polymorphism is that it lets code that you write do things that you didn't even conceive of, at the time you wrote it. If for some reason, I decide that I want to add beveled rectangles to the types of shapes my program can deal with, I can write a new subclass, `BeveledRect`, of class `Shape` and give it its own `redraw()` method. Automatically, code that I wrote previously -- such as the statement `oneShape.redraw()` -- can now suddenly start drawing beveled rectangles, even though the beveled rectangle class didn't exist when I wrote the statement!

> In the statement "`oneShape.redraw();`", the `redraw` message is sent to the object `oneShape`. Look back at the method from the `Shape` class for changing the color of a shape:

>                void setColor(Color newColor) {
>                   color = newColor; // change value of instance variable
>                   redraw(); // redraw shape, which will appear in new color
>                }

> A `redraw` message is sent here, but which object is it sent to? Well, the `setColor` method is itself a message that was sent to some object. The answer is that the `redraw` message is sent to that same object, the one that received the `setColor` message. If that object is a rectangle, then it is the `redraw()` method from the `Rectangle` class that is executed. If the object is an oval, then it is the `redraw()` method from the `Oval` class. This is what you should expect, but it means that the `redraw();` statement in the `setColor()` method does not necessarily call the `redraw()` method in the `Shape` class! The `redraw()` method that is executed could be in any subclass of `Shape`.

> Again, this is not a real surprise if you think about it in the right way. Remember that an instance method is always contained in an object. The class only contains the source code for the method. When a `Rectangle` object is created, it contains a `redraw()` method. The source code for that method is in the `Rectangle` class. The object also contains a `setColor()` method. Since the `Rectangle` class does not define a `setColor()` method, the source code for the rectangle's `setColor()` method comes from the superclass, `Shape`. But even though the source codes for the two methods are in different classes, the methods themselves are part of the same object. When the rectangle's `setColor()` method is executed and calls `redraw()`, the `redraw()` method that is executed is the one in the same object.

> Whenever a `Rectangle`, `Oval`, or `RoundRect` object has to draw itself, it is the `redraw()` method in the appropriate class that is executed. This leaves open the question, What does the `redraw()` method in the `Shape` class do? How should it be defined?

> The answer may be surprising: We should leave it blank! The fact is that the class `Shape` represents the abstract idea of a shape, and there is no way to draw such a thing. Only particular, concrete shapes like rectangles and ovals can be drawn. So, why should there even be a `redraw()` method in the `Shape` class? Well, it has to be there, or it would be illegal to call it in the `setColor()` method of the `Shape` class, and it would be illegal to write "`oneShape.redraw()`;", where `oneShape` is a variable of type `Shape`. The computer would say, `oneShape` is a variable of type `Shape` and there's no `redraw()` method in the `Shape` class.

> Nevertheless the version of `redraw()` in the `Shape` class will never be called. In fact, if you think about it, there can never be any reason to construct an actual object of type `Shape`! You can have variables of type `Shape`, but the objects they refer to will always belong to one of the subclasses of `Shape`. We say that `Shape` is an abstract class. An abstract class is one that is not used to construct objects, but only as a basis for making subclasses. An abstract class exists only to express the common properties of all its subclasses.

> Similarly, we could say that the `redraw()` method in class `Shape` is an abstract method, since it is never meant to be called. In fact, there is nothing for it to do -- any actual redrawing is done by `redraw()` methods in the subclasses of `Shape`. The `redraw()` method in `Shape` has to be there. But it is there only to tell the computer that all `Shapes` understand the `redraw` message. As an abstract method, it exists merely to specify the common interface of all the actual, concrete versions of `redraw()` in the subclasses of `Shape`. There is no reason for the abstract `redraw()` in class `Shape` to contain any code at all.

> `Shape` and its `redraw()` method are semantically abstract. You can also tell the computer, syntactically, that they are abstract by adding the modifier "`abstract`" to their definitions. For an abstract method, the block of code that gives the implementation of an ordinary method is replaced by a semicolon. An implementation must be provided for the abstract method in any concrete subclass of the abstract class. Here's what the `Shape` class would look like as an abstract class:

>            abstract class Shape {

>                Color color;   // color of shape.

>                void setColor(Color newColor) {
>                      // method to change the color of the shape
>                   color = newColor; // change value of instance variable
>                   redraw(); // redraw shape, which will appear in new color
>                }

>                abstract void redraw();
>                      // abstract method -- must be defined in
>                      // concrete subclasses

>                . . .          // more instance variables and methods

>            } // end of class Shape

> Once you have done this, it becomes illegal to try to create actual objects of type `Shape`, and the computer will report an error if you try to do so.

> In Java, every class that you declare has a superclass. If you don't specify a superclass, then the superclass is automatically taken to be `Object`, a predefined class that is part of the package `java.lang`. (The class `Object` itself has no superclass, but it is the only class that has this property.) Thus,

> `class myClass { . . .`

> is exactly equivalent to

> `class myClass extends Object { . . .`

> Every other class is, directly or indirectly, a subclass of `Object`. This means that any object, belonging to any class whatsoever, can be assigned to a variable of type `Object`. The class `Object` represents very general properties that are shared by all objects, belonging to any class. `Object` is the most abstract class of all!

> The `Object` class actually finds a use in some cases where objects of a very general sort are being manipulated. For example, java has a standard class, `java.util.Vector`, that represents a list of `Objects`. (The `Vector` class is in the package `java.util`. If you want to use this class in a program you write, you would ordinarily use an `import` statement to make it possible to use the short name, `Vector`, instead of the full name, `java.util.Vector`. See Section 4.5 for a discussion of packages and `import`.) The `Vector` class is very convenient, because a `Vector` can hold any number of objects, and it will grow, when necessary, as objects are added to it. Since the items in the list are of type `Object`, the list can actually hold objects of any type.

> A program that wants to keep track of various `Shapes` that have been drawn on the screen can store those shapes in a `Vector`. Suppose that the `Vector` is named `listOfShapes`. A shape, `oneShape`, can be added to the end of the list by calling the instance method "`listOfShapes.addElement(oneShape);`". The shape could be removed from the list with "`listOfShapes.removeElement(oneShape);`". The number of shapes in the list is given by the function "`listOfShapes.size()`". And it is possible to retrieve the i-th object from the list with the function call "`listOfShapes.elementAt(i)`". (Items in the list are numbered from 0 to `listOfShapes.size() - 1`.) However, note that this method returns an `Object`, not a `Shape`. (Of course, the people who wrote the `Vector` class didn't even know about `Shapes`, so the method they wrote could hardly have a return type of `Shape`!) Since you know that the items in the list are, in fact, `Shapes` and not just `Objects`, you can type-cast the `Object` returned by `listOfShapes.elementAt(i)` to be a value of type `Shape`:

> `oneShape = (Shape)listOfShapes.elementAt(i);`

> Let's say, for example, that you want to redraw all the shapes in the list. You could do this with a simple `for` loop, which is lovely example of object-oriented programming and polymorphism:

>              for (int i = 0; i < listOfShapes.size(); i++) {
>                 Shape s;  // i-th element of the list, considered as a Shape
>                 s = (Shape)listOfShapes.elementAt(i);
>                 s.redraw();
>              }

> It might be worthwhile to look at an applet that actually uses an abstract `Shape` class and a `Vector` to hold a list of shapes:

> Sorry, your browser doesn't
> support Java.

> If you click one of the buttons along the bottom of this applet, a shape will be added to the screen in the upper left corner of the applet. The color of the shape is given by the "Choice menu" in the lower right. Once a shape is on the screen, you can drag it around with the mouse. A shape will maintain the same front-to-back order with respect to other shapes on the screen, even while you are dragging it. However, you can move a shape out in front of all the other shapes if you hold down the shift key as you click on it.

> In this applet the only time when the actual class of a shape is used is when that shape is added to the screen. Once the shape has been created, it is manipulated entirely as an abstract shape. The routine that implements dragging, for example, works only with variables of type `Shape`. As the `Shape` is being dragged, the dragging routine just calls the `Shape's` draw method each time the shape has to be drawn, so it doesn't have to know how to draw the shape or even what type of shape it is. The object is responsible for drawing itself. If I wanted to add a new type of shape to the program, I would define a new subclass of `Shape`, add another button to the applet, and program the button to add the correct type of shape to the screen. No other changes in the programming would be necessary.

> You might want to look at the source code for this applet, ShapeDraw.java, even though you won't be able to understand all of it at this time. Even the definitions of the shape classes are somewhat different from those I described in this chapter. (For example, the `draw()` method used in the applet has a parameter of type `Graphics`. This parameter is required because of the way Java handles all drawing.) I'll return to this example in later chapters when you know more about applets. However, it would still be worthwhile to look at the definition of the `Shape` class and its subclasses in the source code for the applet. You might also check how a `Vector` is used to hold a list of shapes.

[ Next Section | Previous Section | Chapter Index | Main Index ]