CS 101 (Spring 2000)
Lecture 27
Subclassing

When the definition of one class is very similar to the definition of another, it is a good idea to examine their relationship.

For example, consider the notions of classes A and B. If it can be said that every instance of B is-a possible instance of A, then this is-a relationship is an indication that class B can be defined simply by extending class A.

The java syntax for this is:

public class B extends class A {

   /*  definition of class B in excess of class A's definition */

}
By using the extends clause, every non-private method and instance variable of class A is available to class B, without having to define them explicitly in class B.

As an example, let's consider a simple Parallelogram class, defined below.

public class Parallelogram {
  protected int length, width, angle;

  protected Triangle() {    // provided for subclasses
      this(0,0,0);
  }

  public Triangle(int l, int w, int a) {
     length = l;
     width  = w;
     angle  = a;
  }

  public int circumference() {
     return length + width + length + width;
  }

}

We have provided a default constructor for Parallelogram, namely Parallelogram(). This constructor operates by calling the main constructor, passing it 0 for its parameters. The syntax for one constructor calling another is this(...), where the parameters must match the desired constructor.

This default constructor is not useful in general, but could be used by subclasses of Parallelogram. We therefore mark it as protected so it is available only to subclasses of Parallelogram.

Suppose we now need a Rhombus class. Because every Rhombus is-a Parallelogram, we can obtain Rhombus by extending Parallelogram.

public class Rhombus extends Parallelogram {
   protected Rhombus() {  // provided for subclasses
      this(0,0);
   }

   public Rhombus(int size, int angle) {
      super(size, size, angle);
   }
}
public class Rhombus extends Parallelogram {
   protected Rhombus() {  // provided for subclasses
      this(0,0);
   }

   public Rhombus(int size, int angle) {
      /* Default super() constructor called 
         automaticaly because we didn't call 
         any super constructor ourselves.
       */
      length = size;
      width  = size;
      angle  = a;
   }
}
Using the super constructor Using the default super constructor

When one class extends another, the first thing that must happen in the subclass is initialization of its superclass, by calling some constructor in the superclass. On the left, we have explicitly called the Parallelogram constructor that accepts 3 integer parameters. On the right, we did not call any super constructor, so the default one -- the one with no parameters -- is automatically called for us.

Subclassing allows us to reuse code, which saves us time. For example, although Rhombus does not define circumference() directly, it inherits the implementation from its superclass (Parallelogram).

Now suppose we want to introduce a square. Every square is-a paralellogram. But it is also true that every square is-a rhombus. We gain more reuse by extending Rhombus, thus:

public class Square extends Rhombus {
   protected Square() {  // for subclasses
      this(0);
   }
   public Square(int size) {
      super(size, 90);
   }
}

We make a square by making a rhombus whose angle is 90 degrees.

Think about:

  1. How you would subclass Square to make a unit-square: a square whose sides are all 1 unit in length?
  2. What would our system of shapes look like if we had subclassed Parallelogram to obtain Rectangle instead of Rhombus? Where would Square fit in? How would we introduce Rhombus later?


Last modified 08:33:32 CST 30 March 1999 by Ron K. Cytron