Inheritance

public class TailList extends SList {
    // The "head" and "size" fields are inherited from SList.
    private SListNode tail;

Inheritance and Constructors

It first executes the code in the SList() constructor before it it executes the TailList constructor.

The zero-parameter constructor gets called by default. Use super keyword to call other constructor explicitly.

    public TailList(int x) {
      super(x); // must be the first statement in the constructor
      tail = null;
    }

Invoking Overridden Methods

Ordinary superclass method can be anywhere.

    public void insertFront(Object obj) {
      super.insertFront(obj);             // Insert at the front of the list.
      if (size == 1) {                    // If necessary,
        tail = head;                      //   adjust the tail reference.
      }
    }
  }

The protected Keyword

  • between public and private
  • private fields are not visible to the subclasses

Class Hierarchies

  • Subclassing is transitive.
  • Every class is a subclass of the Object class.

Dynamic Method Lookup

Every TailList IS an SList.

  SList s = new TailList();         // Groovy.
  TailList t = new SList();         // COMPILE-TIME ERROR.
  • Static type. The type of a variable.
  • Dynamic type. The class of the object the variable references.

In the code above, the static type of s is SList, and the dynamic type of s is TailList.

When invoke an overriden method, Java calls the mothod for the object's dynamic type, regardless of the variable's static type.

  SList s = new TailList();
  s.insertEnd(obj); // Call TailList.insertEnd()
  s = new SList();
  s.insertEnd(obj); // Call SList.insertEnd()

This is called dynamic method lookup, because Java automatically looks up the right method for a given object at run-time.

-------------------------------------------------------------------------------
| WHY DYNAMIC METHOD LOOKUP MATTERS             (Worth reading and rereading) |
|                                                                             |
| Suppose you have a method (in any class) that sorts an SList using only     |
| SList method calls (but doesn't construct any SLists).  Your method now     |
| sorts TailLists too, with no changes.                                       |
|                                                                             |
| Suppose you've written a class--let's call it RunLengthEncoding--that uses  |
| SLists extensively.  By changing the constructors so that they create       |
| TailLists instead of SLists, your class immediately realizes the            |
| performance improvement that TailLists provide--without changing anything   |
| else in the RunLengthEncoding class.                                        |
-------------------------------------------------------------------------------

Subtleties of Inheritance

(1) Suppose we write a new method in the TailList class called eatTail(). We can't call eatTail on an SList. We can't even call eatTail on a variable of type SList that references a TailList.

TailList t = new TailList();
t.eatTail();                      // Groovy.
SList s = new TailList();         // Groovy--every TailList is an SList.
s.eatTail();                      // COMPILE-TIME ERROR.

Why? Because not every object of class SList has an "eatTail()" method, so Java can't use dynamic method lookup on the variable s.

But if we define eatTail() in SList instead, the statements above compile and run without errors, even if no eatTail() method is defined in class TailList. (TailList inherits eatTail() from SList.)

(2) I pointed out earlier that you can't assign an SList object to a TailList variable. The rules are more complicated when you assign one variable to another.

SList s;
TailList t = new TailList();
s = t;                            // Groovy.
t = s;                            // COMPILE-TIME ERROR.
t = (TailList) s;                 // Groovy.
s = new SList();
t = (TailList) s;                 // RUN-TIME ERROR:  ClassCastException.

Why does the compiler reject "t = s", but accept "t = (TailList) s"? It refuses "t = s" because not every SList is a TailList, and it wants you to confirm that you're not making a thoughtless mistake. The cast in the latter statement is your way of reassuring the compiler that you've designed the program to make sure that the SList s will always be a TailList.

If you're wrong, Java will find out when you run the program, and will crash with a "ClassCastException" error message. The error occurs only at run-time because Java cannot tell in advance what class of object s will reference.

(3) Java has an "instanceof" operator that tells you whether an object is of a specific class. WARNING: The "o" in "instanceof" is not capitalized.

if (s instanceof TailList) {
  t = (TailList) s;
}

This instanceof operation will return false if s is null or doesn't reference a TailList. It returns true if s references a TailList object--even if it's a subclass of TailList.

results matching ""

    No results matching ""