Chapter 9

Interfaces and Polymorhism


Chapter Goals

Modifying DataSet for Bank Accounts

public class DataSet // modified for BankAccount objects
{
. . .
public void add(BankAccount x)
{
sum = sum + x.getBalance();
if (count == 0
|| maximum.getBalance() < x.getBalance())
maximum = x;
count++;
}

public BankAccount getMaximum()
{
return maximum;
}

private double sum;
private BankAccount maximum;
private int count;
}

Modifying DataSet for Coins

public class DataSet // modified for Coin objects
{
. . .
public void add(Coin x)
{
sum = sum + x.getValue();
if (count == 0
|| maximum.getValue() < x.getValue())
maximum = x;
count++;
}

public Coin getMaximum()
{
return maximum;
}

private double sum;
private Coin maximum;
private int count;
}

Measurable Interface

Interfaces vs. Classes

Generic DataSet for Measurable Objects


public class DataSet // modified for Coin objects
{
. . .
public void add(Measurable x)
{
sum = sum + x.getMeasure();
if (count == 0
|| maximum.getMeasure() < x.getMeasure())
maximum = x;
count++;
}

public Measurable getMaximum()
{
return maximum;
}

private double sum;
private Measurable maximum;
private int count;
}

Realizing an Interface

Making BankAccount and Coin Classes Measurable

class BankAccount implements Measurable
{
public double getMeasure()
{
return balance;
}
additional methods and fields
}
class Coin implements Measurable
{
public double getMeasure()
{
return value;
}
additional methods and fields
}

File DataSetTest.java

1/**
2   This program tests the DataSet class.
3*/
4public class DataSetTest
5{
6   public static void main(String[] args)
7   {
8
9      DataSet bankData = new DataSet();
10
11      bankData.add(new BankAccount(0));
12      bankData.add(new BankAccount(10000));
13      bankData.add(new BankAccount(2000));
14
15      System.out.println("Average balance = " 
16         + bankData.getAverage());
17      Measurable max = bankData.getMaximum();
18      System.out.println("Highest balance = " 
19         + max.getMeasure());
20
21      DataSet coinData = new DataSet();
22
23      coinData.add(new Coin(0.25, "quarter"));
24      coinData.add(new Coin(0.1, "dime"));
25      coinData.add(new Coin(0.05, "nickel"));
26
27      System.out.println("Average coin value = " 
28         + coinData.getAverage());
29      max = coinData.getMaximum();
30      System.out.println("Highest coin value = " 
31         + max.getMeasure());
32   }
33}

UML Diagram of DataSet and Related Classes


Syntax 9.1: Defining an Interface


  public interface InterfaceName
{
   method signatures

}

Example:

  public interface Measurable
{
   double getMeasure();
}

Purpose:

To define an interface and its method signatures. The methods are automatically public.

Syntax 9.2: Implementing an Interface

  public class ClassName
    implementsInterfaceName, InterfaceName, ...
{
   methods
   instance variables
}

Example:

  public class BankAccount
   implements Measurable
{
   // other BankAccount methods
   public double getMeasure()
   {
      // method implementation
   }
}

Purpose:

To define a new class that implements the methods of an interface

Converting Between Types

Casts

The instanceof Operator

Syntax 9.3: The instanceof Operator

  object instanceof ClassName

Example:

  if (x instanceof Coin)
{
   Coin c = (Coin)x;
}

Purpose:

To return true if the object is an instance of ClassName (or one of its subclasses), false otherwise

Polymorphism

Polymorphism

Using a Strategy Interface

Using a Strategy Interface

public void add(Object x)
{
sum = sum + measurer.measure(x);
if (count == 0
|| measurer.measure(maximum)measurer.measure(x))
maximum = x;
count++;
}

Using a Strategy Interface


class RectangleMeasurer implements Measurer
{
public double measure(Object anObject)
{
Rectangle aRectangle = (Rectangle)anObject;
double area = aRectangle.getWidth() * aRectangle.getHeight();
return area;
}
}

UML Diagram of Measurer Interface and Related Classes


Inner Classes

public static void main(String[] args)
{
class RectangleMeasurer implements Measurer
{
. . .
}
Measurer m = new RectangleMeasurer();
. . .
// RectangleMeasurer class not used beyond this point
}

File DataSet.java

1/**
2   Computes the average of a set of data values.
3*/
4public class DataSet
5{
6   /**
7      Constructs an empty data set with a given measurer
8      @param aMeasurer the measurer that is used to measure data values
9   */
10   public DataSet(Measurer aMeasurer)
11   {
12      sum = 0;
13      count = 0;
14      maximum = null;
15      measurer = aMeasurer;
16   }
17
18   /**
19      Adds a data value to the data set
20      @param x a data value
21   */
22   public void add(Object x)
23   {
24      sum = sum + measurer.measure(x);
25      if (count == 0 
26         || measurer.measure(maximum) < measurer.measure(x))
27         maximum = x;
28      count++;
29   }
30
31   /**
32      Gets the average of the added data.
33      @return the average or 0 if no data has been added
34   */
35   public double getAverage()
36   {
37      if (count == 0) return 0;
38      else return sum / count;
39   }
40
41   /**
42      Gets the largest of the added data.
43      @return the maximum or 0 if no data has been added
44   */
45   public Object getMaximum()
46   {
47      return maximum;
48   }
49
50   private double sum;
51   private Object maximum;
52   private int count;
53   private Measurer measurer;
54}

File DataSetTest.java

1import java.awt.Rectangle;
2
3/**
4   This program demonstrates the use of a Measurer.
5*/
6public class DataSetTest
7{
8   public static void main(String[] args)
9   {
10      class RectangleMeasurer implements Measurer
11      {
12         public double measure(Object anObject)
13         {
14            Rectangle aRectangle = (Rectangle)anObject;
15            double area 
16               = aRectangle.getWidth() * aRectangle.getHeight();
17            return area;
18         }
19      }
20
21      Measurer m = new RectangleMeasurer();
22
23      DataSet data = new DataSet(m);
24
25      data.add(new Rectangle(5, 10, 20, 30));
26      data.add(new Rectangle(10, 20, 30, 40));
27      data.add(new Rectangle(20, 30, 5, 10));
28
29      System.out.println("Average area = " + data.getAverage());
30      Rectangle max = (Rectangle)data.getMaximum();
31      System.out.println("Maximum area = " + max);
32   }
33}

File Measurer.java

1/**
2   Describes any class whose objects can measure other objects.
3*/
4public interface Measurer
5{
6   /**
7      Computes the measure of an object.
8      @param anObject the object to be measured
9      @return the measure
10   */
11   double measure(Object anObject);
12}

Syntax 9.4: Inner Classes

  Declared inside a method
class OuterClassName
{
   method signature
   {
      . . .
      class InnerClassName
      {
         nethods
         fields

      }
      . . .
   }
   . . .
}
Declared inside a class

class OuterClassName
{
   nethods
   fields

   accessSpecifier class InnerClassName
   {
      nethods
      fields

   }
   . . .
}



Example:

  public class Test
{
   public static void main(String[] args)
   {
      class RectangleMeasurer implements Measurer
      {
         . . .
      }
   }
}

Purpose:

To define an inner class whose methods have access to the same variables and methods as the outer class methods

Processing Timer Events

Example: Countdown

File TimerTest.java

1import java.awt.event.ActionEvent;
2import java.awt.event.ActionListener;
3import javax.swing.JOptionPane;
4import javax.swing.Timer;
5
6/**
7   This program tests the Timer class.
8*/
9public class TimerTest
10{
11   public static void main(String[] args)
12   {
13      class CountDown implements ActionListener
14      {
15         public CountDown(int initialCount)
16         {
17            count = initialCount;
18         }
19
20         public void actionPerformed(ActionEvent event)
21         {
22            if (count >= 0)
23               System.out.println(count);
24            if (count == 0)
25               System.out.println("Liftoff!");
26            count--;
27         }
28
29         private int count;
30      }
31
32      CountDown listener = new CountDown(10);
33
34      final int DELAY = 1000; // milliseconds between timer ticks
35      Timer t = new Timer(DELAY, listener);
36      t.start();
37
38      JOptionPane.showMessageDialog(null, "Quit?");
39      System.exit(0);
40   }
41}

Example: Add Interest

Inner Class Can Access Outer Variables

class InterestAdder implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
double interest = account.getBalance() * RATE / 100;
account.deposit(interest);
System.out.println("Balance = " + account.getBalance());
}
}

File TimerTest.java

1import java.awt.event.ActionEvent;
2import java.awt.event.ActionListener;
3import javax.swing.JOptionPane;
4import javax.swing.Timer;
5
6/**
7   This program uses a timer to add interest to a bank 
8   account once per second.
9*/
10public class TimerTest
11{
12   public static void main(String[] args)
13   {
14      final BankAccount account = new BankAccount(1000);
15
16      class InterestAdder implements ActionListener
17      {
18         public void actionPerformed(ActionEvent event)
19         {
20            double interest = account.getBalance() * RATE / 100;
21            account.deposit(interest);
22            System.out.println("Balance = " 
23               + account.getBalance());
24         }
25      }
26
27      InterestAdder listener = new InterestAdder();
28
29      final int DELAY = 1000; // milliseconds between timer ticks
30      Timer t = new Timer(DELAY, listener);
31      t.start();
32
33      JOptionPane.showMessageDialog(null, "Quit?");
34      System.exit(0);
35   }
36
37   private static final double RATE = 5;
38}

UML Diagram of Timer Classes