RU beehive logo ITEC dept promo banner
ITEC 120
2007fall
ibarland,
jdymacek

homeinfoexamslectureslabshws
RecipeLawsliessyntaxjava.lang docsjava.util docs

lect15b
Interfaces

Review inheritance


Calling a superclass's method

Interface vs. abstract class

  1. Like an abstract class, interfaces are useful only for extending; you can't make an instance of the interface itself.
  2. An interface is like a class except that it contains no code -- it only has method signatures (and static final constants).
  3. By comparison, an (abstract) class can contain fields and actual code, which gets shared.
  4. A class can only extend one superclass (in Java).
  5. A class can implement many interfaces.
(ii) and (iii) are advantages to abstract classes, but (iv) and (v) are an advantage to interfaces. We'll come back to this topic below, trying to get the best of both worlds.

Example: Suppose we want to sort a list of Treasures by weight (ascending). We write some complicated to do so (perhaps after taking ITEC 220); it will involve statements like

  List<Treasure> sort( List<Treasure> items ) {
    // ...code, perhaps including loops...

    if (t1.getWeight() < t2.getWeight()) 

    // ...
    }
(where t1 and t2 are local variables, perhaps inside a loop).

Then, later, we want to sort a list of Dogs, by age (ascending). This is practically the same problem; the only difference is that this version will involve statements like if (d1.getAge() < d2.getAge()) . Yech! … nearly-repeated-code which is impossible to factor out because one deals with getWeight and another with getAge.

Interfaces, to the rescue! In particular, the the Comparable interface. If both Dogs and Treasures implement the interface, then our sorting code can include

  if (e1.compareTo(e2) < 0) /* think: "e1 < e2" */ 
We'd have to have implement each of these
code Dog implements Comparable<Dog> {
  //... other Dog fields/methods

  public int compareTo( Dog other ) {
    if (this.getAge() < other.getAge()) {
      return -1;  // Any negative number is good enough to satisfy the interface.
      }
    else if (this.getAge() == other.getAge()) {
      return 0;
      }
    else if (this.getAge() > other.getAge()) {
      return +1;  // Any positive number will suffice.
      }
    else {
      System.err.println( "Shouldn't reach this far." );
      return 0;  // Better than returning a bad answer: Throw an exception.
      }
    }
    
  }
(Challenge: Can you find a one-line way to implement this method?) And Treasure would have a similarly have a method compareTo.

Note that we don't want to have these two classes both inherit from some common superclass, each overriding compareTo appropriately. You might argue that perhaps class Object should've had including compareTo in the same way they already included toString and equals. However, there will always be new behaviors which people might want in the future, so having interfaces gives us, as programmers, a power different from abstract classes.

Another example: An example: Similarly, java.util.List is an interface, which is implemented by LinkedList, as well as a class named ArrayList.1 This means that if we change the signature String TreasureListToString( LinkedList<Treasure> loot ) to String TreasureListToString( List<Treasure> loot ) then our function will be able to handle both LinkedLists, as well as ArrayLists, as well as any other List variant people might invent in the future!


The Delegate Pattern

How to fake multiple inheritance, if Java doesn't allow it? That is, suppose we have Guard Dogs, which are like Dogs but they have some additional guard behaviours:

  String threatenSound();             // How does this guard threaten?
  boolean deters(Animal anAnimal);    // Does this guard succesfully deter anAnimal?
In fact, we quickly realize that being a guard is not specific to being a Dog; we could certainly have guard-cats and guard-pythons. In fact, some guards aren't even animals -- an alarm system can make a threatening sound and can deter some (human) animals. So we should have Guard be its own class. (There is code for the Guard methods.

But now we have the problem, that for a class GuardDog we want to Extend two different classes.

This is better, but not a perfect solution. For instance: And, if we want to make a SmallGuardDog, what class should it extend — GuardDog, or SmallDog? Either answer is unsatisfactory. Delegate pattern can still help, though it's starting to become cumbersome: for every class we can have an interface, and then have SmallGuardDog extend SmallDog implement IGuardDog2, and it will have a GuardDog2 delegate instance inside of it. This avoids repeated code (at the cost of our mental overhead).

1 (Its name is a bit confusing; an ArrayList is not an array! It's a List, since it can get(index) and add and answer size() and isEmpty(). That is, it implements the List interface, so therefore an ArrayList is a List. You can't use square-brackets or the field length with ArrayList. It derives its name from the fact that under the hood, it uses arrays to help it organize its contents. But we don't care about how it works, as long as it meets its interface.      

homeinfoexamslectureslabshws
RecipeLawsliessyntaxjava.lang docsjava.util docs


©2007, Ian Barland, Radford University
Last modified 2007.Dec.05 (Wed)
Please mail any suggestions
(incl. typos, broken links)
to iba�rlandrad�ford.edu
Powered by PLT Scheme