Laboratory: Inheritance
CSC 207 Algorithms and Object Oriented Design Spring 2011

Summary: In this lab, you will explore inheritance in Java by building and extending some simple classes.

Preparation

  1. Create a directory for this lab:
      mkdir somewhere/inheritance
  2. Go to your new directory:
      cd somewhere/inheritance
  3. Copy the files for this lab to your new directory:
      cp ~weinman/public_html/courses/CSC207/2011S/labs/code/inheritance/WhatCounts.java .
      cp ~weinman/public_html/courses/CSC207/2011S/labs/code/inheritance/WhatElseCounts.java .

Exercises

Exercise 1

To start, we will create an interface called Counter that specifies capabilities of objects that count things, starting at some value.

The interface should contain three public methods:

Exercise 2

Because different counters might handle their incrementing differently (e.g. arithmetically versus geometrically), but all likely need to track a count and starting value, we can root a class hierarchy with an abstract base class.

Create a new abstract class, AbstractCounter, that implements the Counter interface and contains:

Exercise 3

Finally, we want a concrete version of a counter that simply counts in the usual fashion, by adding one to the count with each increment operation.

  1. Create a new concrete class, BasicCounter that extends AbstractCounter. It should have:
    • One constructor that takes a starting value as a parameter. Use super to call the instructor of the parent class.
    • An implementation of increment() that adds 1 to count.
  2. Inspect the class WhatCounts.java that you copied in the lab preparations. What output do you expect?
  3. Verify your answer by compiling and running WhatCounts.
  4. Change the declaration of alpha in WhatCounts.java so that it reads:
    Counter alpha = new AbstractCounter(0);
  5. What effect to you expect this change to have? Confirm or refute your answer experimentally.
  6. Restore the initialization of alpha to a BasicCounter.

Exercise 4

  1. Create a new derived class, DecrementableCounter, that has the following form:
    DecrementableCounter.java
    /**
     * A Counter that supports decrementing.
     *
     * @author YOUR NAME HERE
     */
    public class DecrementableCounter
      extends BasicCounter
    {
    
      /**
       * Create a new decrementable counter starting from the specified value.
       *
       * @param start Specified value for this counter to start counting from
       */
      public DecrementableCounter(int start)
      {
        super(start);
      } // DecrementableCounter(int)
    
    } // class DecrementableCounter
  2. Change the initialization of gamma in WhatCounts.java so that it reads
    Counter gamma = new DecrementableCounter(-5);
  3. What effect to you expect this change to have? Confirm or refute your answer experimentally.
  4. Change the initialization of gamma so that it reads
    DecrementableCounter gamma = new Counter(-5);
  5. What effect to you expect this change to have? Confirm or refute your answer experimentally.
  6. Restore the initialization of gamma to
    Counter gamma = new DecrementableCounter(-5);
  7. Add a decrement() method to DecrementableCounter This method should subtract one from the count field.
  8. Add lines to WhatCounts to test that method.

Exercise 5

  1. Create a new class, LimitedCounter, that has the following form
    LimitedCounter.java
    /**
     * A Counter whose count has an upper bound.
     *
     * @author YOUR NAME HERE
     */
    public class LimitedCounter
      extends BasicCounter
    {
      int limit; /** Limit for this counter */
    
      
      /**
       * Create a new limited counter having the limit and starting
       * from the specified value.
       *
       * @param start Specified value for this counter to start counting from
       * @param limit Specified limit for this counter
       */
      public LimitedCounter(int start, int limit)
      {
        super(start);
        this.limit = limit;
      } // LimitedCounter(int, int)
    } // class LimitedCounter 
  2. Override the increment method so that it throws an IllegalStateException when count exceeds limit.
  3. Update WhatCounts so that the initialization of alpha reads
    Counter alpha = new LimitedCounter(0);
  4. What effect do you expect this change to have? Confirm or refute your prediction experimentally.
  5. Determine the results of changing the initialization of alpha to
    Counter alpha = new LimitedCounter(-5,3);
  6. Run your current version of WhatCounts.
  7. Swap the two lines in the constructor for LimitedCounter and determine what errors, if any, you get. Why do you think that is?
  8. Restore the constructor.

Exercise 6

  1. Create a new class, DoubleCounter, that has the following form:
    DoubleCounter.java
    public class DoubleCounter
      extends BasicCounter
    {
    
    } // class DoubleCounter 
  2. Compile your new class. What error messages, if any, do you receive? If you do not understand the results, check the notes for this exercise.
  3. Insert a constructor for DoubleCounter of the following form
      public DoubleCounter(int start)
      {
        super(start);
      } // DoubleCounter(int)
  4. Update WhatCounts so that the initialization of beta reads
    Counter beta = new DoubleCounter(123);
  5. What effect do you expect this change to have? Confirm or refute your prediction experimentally.
  6. Override the increment method by inserting the following code into DoubleCounter
      public void increment()
        throws IllegalStateException
      { 
        super.increment();
        super.increment();
      }
  7. What effect do you expect this change to have in WhatCounts? Confirm or refute your prediction experimentally.

Exercise 7

  1. Make LimitedCounter a subclass of DoubleCounter rather than a subclass of Counter. (That is, change the line that reads extends Counter to read extends DoubleCounter.)
  2. What effect, if any, do you expect that change to have? Confirm or refute your results experimentally.

Exercise 8

  1. Inspect the class WhatElseCounts.java that you copied in the lab preparations. What output do you expect?
  2. Confirm or refute your hypothesis experimentally by compiling and running WhatElseCounts. Can you generalize the pattern?

    If you are having trouble, the notes on this exercise gives some background.

Exercise Notes

Notes on Exercise 4

Until you write a constructor for a class, Java implicitly provides a no-argument constructor. The consequence is that all member fields are constructed with their default values (e.g., zero, false, or null). Once you write a constructor, however, this default constructor is no longer available.

Similarly, unless there is an explicit call to the base class's constructor, each constructor of a derived class will begin with an implicit call to super(), the base class's no-argument constructor. If this constructor does not exist, the compiler generates an error.

Notes on Exercise 6

As you have likely noticed when experimenting with WhatCounts the runtime type of a polymorphic reference determines which implementation of an object method is used. Thus, even though beta is declared as a BasicCounter, when its increment method is called, the value is "doubly" incremented because the runtime type of the object it refers to is DoubleCounter. This is referred to as dynamic dispatch, and it is covered in more detail in Weiss 4.9.

In contrast, when methods are overloaded (as opposed to overridden), finding the appropriate method via signature matching strictly uses the static type of the variables in question.

Created: Samuel A. Rebelsky, 2 March 2006
Modified: Jerod Weinman, 17 January 2011
Modified: Jerod Weinman, 2 February 2011
Adopted from
Espresso: Laboratory: Inheritance