An IntList class

It's now time for you to apply the concepts of inheritance and polymorphism.

The IntList class

Consider the class IntList, which is a growable array of ints -- it works like an ArrayList but for int primitives. Go ahead and bring this class into your Eclipse project if you haven't already. It is based on the idea of a partially filled array as seen in class.

An example of how we might use IntList follows:

public class IntListTest {

   public static void main(String[] args) {
      
      IntList list = new IntList();
      
      list.add(5);
      list.add(4);
      list.add(3);
      System.out.println(list);
      System.out.println("Size: " + list.size());
      System.out.println("Min: " + list.getMinimum());
      System.out.println("Max: " + list.getMaximum());
   }
}

Modifying behavior in a subclass

Say you find a few months down the road that IntList doesn't quite do exactly what you need for a certain problem. For this new problem, you'd like the list to stay sorted in ascending order (e.g., 1, 4, 10) as you add things to it. That is, instead of just adding each element at the end of the list, or at an arbitrary position, we'll find the right spot to insert it so that the list stays in order. The existing IntList code works pretty well and handles resizing the array for you, so you make a new class IntListSorted that extends IntList, but overrides the add and insert methods.

public class IntListSorted extends IntList
{
  /**
   * Adds a new item to this list, inserting it so that
   * the list remains sorted.
   */
  @Override
  public void add(int newItem)
  {
    if (size() == 0 || get(size() - 1) <= newItem)
    {
      super.add(newItem);
    }
    else
    {
      int i = size();
      while (i > 0 && newItem < get(i - 1))
      {
        i -= 1;
      }
      
      // now i is 0, or newItem >= list[i - 1], so put the new
      // element at position i
      super.insert(i, newItem);
    }
  }
  
  /**
   * Inserts a new item in this list, inserting it so that
   * the list remains sorted.  (The given index is ignored.)
   */
  @Override
  public void insert(int index, int newItem)
  {
    this.add(newItem);
  }
}

Notice how the new add method overrides the superclass's add method, but still calls the superclass version with super.add to do the actual work of inserting the element and possibly growing the array.

Certainly we could have ignored inheritance and just copied the code for IntList over into our new IntListSorted class. However, if we found an error in the IntList someday, that would mean it would need to be corrected in at least two places. That's bad.

Checkpoint 1

Okay, now complete these two tasks and show your TA. You can test your code by changing your IntListTest to use an IntListSorted instance instead of an IntList.

  1. You see that your new IntListSorted can find the minimum and maximum values in the list in a much simpler and faster way than the superclass can. Override these methods with this faster approach. Modify your IntListTest class to use an IntListSorted instance instead of an IntList and try it out.
  2. Besides overriding superclass functionality, subclasses can add functionality not available to the superclass. Write a method getMedian that returns the middle element of an IntListSorted. (Note: When the list contains an even number of items, just return the last element in the first half of the list, i.e., the element right before the "center" of the list. For example, in the case of [0, 1, 3, 10], 1 should be returned.) Demonstrate your code by adding additional statements to IntListTest.