Computer Science 15-100 (Sections T & U), Fall 2007
Class Notes:   Inheritance


Logistics

  1. Reading:  L&L Chapter 8 (except 8.6)

  1. Creating Subclasses
  2. Terms:
    1. inheritance, single inheritance, multiple inheritance
    2. base class, parent class, superclass
    3. child class, subclass
    4. extends, derives from, is-a relationship
  3. The Object Class
    1. Classes extend Object by default
  4. The super reference, part 1:  Invoking the superclass's constructor
  5. Visibility and Subclasses (public, default/package, protected, private)
  6. Overriding methods
  7. Bad Idea #1374:  Shadowing instance variables with subclass instance variables
  8. The super reference, part 2:  Invoking overridden methods
  9. For next time...
    1. Class Hierarchies
    2. Read Section 8.5 (of course, read the others, too!):  Designing for Inheritance
    3. final variables, methods, and classes
    4. Time permitting:
      1. Implementing a MouseListener
      2. Extending a MouseAdapter
      3. Using a Timer

Code from class:

// Here is the code we wrote in class today,
// to demonstrate the ideas listed above.

import java.util.ArrayList;
import java.util.Collection;

public class InheritanceDemo { public static void main(String[] args) { Main.main(args); } }


@SuppressWarnings("unchecked")
class UpperCaseArrayList extends ArrayList {
  // this is the default constructor that we effectively created:
  public UpperCaseArrayList() {
    super();  // <-- Call the super constructor that takes no parameters
  }
  
  public UpperCaseArrayList(Collection c) {
    // THIS DOES NOT WORK:  (Does not convert to upper case)
    // super(c); // <-- Call the super constructor that takes a collection
    
    // This DOES work, by calling the superclass's no-parameter constructor
    // and then adding each string in turn
    // super();
    // for (Object obj : c) add(obj);

    // This DOES NOT WORK, because YOU CANNOT CALL A SUPERCLASS CONSTRUCTOR
    // EXCEPT ON THE FIRST LINE
    // Collection upperCase = makeUpperCase(c);
    // super(upperCase);
    
    super(makeUpperCase(c));
  }
  
  private static Collection makeUpperCase(Collection c) {
    ArrayList out = new ArrayList();
    for (Object obj : c) out.add((obj instanceof String) ? ((String)obj).toUpperCase() : obj);
    return out;
  }
  
  // override the default add method of ArrayList
  // so that we convert strings to uppercase first
  public boolean add(Object obj) {
    if (obj instanceof String) {
      // now WE know it is a string, but the COMPILER doesn't!
      // So we CAST it to a String
      obj = ((String)obj).toUpperCase();
    }
    return super.add(obj);
  }
}

@SuppressWarnings("unchecked")
class Main {
  public static void main(String[] args) {
    part2();
  }

  public static void part2() {
    UpperCaseArrayList a = new UpperCaseArrayList(); // <- Use the DEFAULT constructor
    a.add("This"); a.add("is"); a.add("a"); a.add("test"); a.add(55);
    System.out.println(a);

    ArrayList a2 = new ArrayList(a);
    a2.add("wahoo");
    System.out.println(a2);

    // This looks ok...
    UpperCaseArrayList a3 = new UpperCaseArrayList(a);
    a3.add("wahoo");
    System.out.println(a3);

    // but it's not!
    ArrayList b = new ArrayList(); // <- Use the DEFAULT constructor
    b.add("This"); b.add("is"); b.add("a"); b.add("test"); b.add(55);
    System.out.println(b);
    UpperCaseArrayList a4 = new UpperCaseArrayList(b);
    a4.add("wahoo");
    System.out.println(a4);

  }
  
  public static void part1() {
    Object obj;
    obj = "foo";
    System.out.println(obj.toString());
    System.out.println(obj.getClass().getName());
    System.out.println(obj instanceof Object);
    System.out.println(obj instanceof String);
    System.out.println(obj instanceof Integer);
    System.out.println(obj instanceof MyClass);
    obj = 123;  // autoboxed into Integer
    System.out.println(obj.toString());
    System.out.println(obj.getClass().getName());
    System.out.println(obj instanceof Object);
    System.out.println(obj instanceof String);
    System.out.println(obj instanceof Integer);
    System.out.println(obj instanceof MyClass);
    obj = new MyClass();  // proof positive that MyClass is-a Object!
    System.out.println(obj.toString());
    System.out.println(obj.getClass().getName());
    System.out.println(obj instanceof Object);
    System.out.println(obj instanceof String);
    System.out.println(obj instanceof Integer);
    System.out.println(obj instanceof MyClass);
    
    obj = 123;
    System.out.println(obj.toString());
    System.out.println(obj.getClass().getName());
    System.out.println(obj instanceof Object);
    System.out.println(obj instanceof Integer);
    System.out.println(obj instanceof Double);
    System.out.println(obj instanceof Number);
    obj = 123.45;
    System.out.println(obj.toString());
    System.out.println(obj.getClass().getName());
    System.out.println(obj instanceof Object);
    System.out.println(obj instanceof Integer);
    System.out.println(obj instanceof Double);
    System.out.println(obj instanceof Number);
  }

  // overriding Object's toString()
  public String toString() {
    return "I am a MyClass";
  }
}

Carpe diem!