Keywords: current

Next: 1.5.4.1 Overriding equals Up: 1.5 Basic Program Design Previous: 1.5.3.4 A Sample Program

## 1.5.4 Inheritance and the Composite Pattern

Up to this point, we have used methods in Java essentially like functions in a procedural lanuage. What makes object-oriented programming truly powerful is the ability to add new forms of data to our program without modifying any old code. For example, if we later decide to insert links to other directories as additional form of `DeptDirectory` data, we can simply define a new subclass `Link` of `DeptDirectory` with a `subDir` field referring to the embedded directory (which can be searched using the `findAddress` method. The new class must define `findAddress` for the new form of data that it introduces, but none of the existing classes requires any change whatsoever.

In defining a program extension, the added data does not have to be a new subclass of an abstract class like `DeptDirectory`. The new data can be a subclass of an existing concrete class. For example, we could extend our directory program by defined a class EntryWithPosition extending `Entry` with a `String` field `title` specifying the person's title (graduate student, instructor, professor, chair, etc.) and a getter method `getTitle` to retrieve it. No revision of the `Entry` class would be required. Unfortunately, to extract this information using the programming techniques discussed so far, we would have to add a new method `findTitle` to the composite class hierarchy `DeptDirectory`--modifying existing code. We will introduce a design pattern, called the visitor pattern near the end of this chapter that eliminates this problem.

When a class C extends another class D, every instance (non-static) member m of D is automatically an instance member of C with one exception: if C redefines the method m1.4 We say that the instance members of class D are inherited by the subclass C. The linguistic convention of automatically incorporating the instance member definitions of a class in each of its subclasses is called inheritance. If an inherited method m is redefined in class C, we say that the new definition overrides the inherited definition.

We have already made extensive use of a limited form of inheritance in the composite pattern. All of the variant classes of in a composite hierarhcy provide definitions for the abstract methods inherited from the abstract superclass. Recall the `DeptDirectory` and `IntList` programs. When an abstract method from an abstract class is overridden in a concrete subclass (e.g. `findAddress` from `DeptDirectory` in the classes `Empty` and `Cons`), the ``missing'' definition inherited from the abstract class is overridden. This special form of overriding is sometimes called method extension because the inherited meaning of the method (nothing) is extended rather than modified.

When a class C overrides a method m in its superclass D, code in the body of C can still invoke the overridden method m from D using the special notation

> `super.m( ... )`

The feature can be used to add pre-processing and post-processing code to an inherited method m. The overriding definition of m can check or transform its inputs, invoke `super.`m on the transformed inputs, and subsequently check or transform the result produced by the `super`.m call.

It is important to remember that all unqualified member references in inherited code implicitly refer to the implicit method argument `this` which is bound to an instance of the inheriting class! Hence, the meaning of a method call appearing in inherited code changes if the specified method has been overridden! In practice, this semantic convention gives the behavior that programmers expect for instances of subclasses, but it can occasionally produce surprises--particulary if the method overriding is the result of an accidental rather than an intentional name match.

Finger exercise: Load the `superCall` sample program into the DrJava Definitions pane. The body of method `length` in class `Vector` includes calls on the instance method `getLeft` and `getRight`. The class `TranlatedVector` which extends `Vector` contains a `super` call on `length` in its overriding definition of `length`. To what object is `this` bound in the inherited `length` method when it is invoked by the `super` call?

The meaning of field names in inherited code is even more subtle than the meaning of method names, because fields are never overridden. If the extending class C defines a field with the same name as an inherited field, the inherited field is merely ``shadowed'' exactly as it would be by a local variable with the same name. The inherited field still exists in each instance of C and can be accessed by code in the body of C (assuming that it not `private`, see Section 1.5.5) by casting the `C` object to its superclass type D before extracting the field.

If you follow the programming guidelines recommended in this monograph you can generally avoid the pathologies discussed in the preceding paragraph. According to our stylistic rules, field references should never span class boundaries (with the exception of visitor objects discussed below in Section 1.10). Hence, shadowed members are only accessed through getter methods inherited from the superclass. The only field that can be accessed directly is the one defined in the current class.

Subsections

- 1.5.4.1 Overriding `equals`

Next: 1.5.4.1 Overriding equals Up: 1.5 Basic Program Design Previous: 1.5.3.4 A Sample Program