Chapter 6

Interfaces


CONTENTS


In this chapter you'll learn how to use Java interfaces to provide a common set of methods by which a group of classes can be accessed and to implement features of multiple inheritance. You'll cover the use of interface constants and learn how to declare objects using interface types. You will also learn how to extend and combine interfaces. When you finish this chapter, you'll be able to use interfaces with your Java classes.

The Purpose of Java Interfaces

The Java interface construct is borrowed from the Objective-C protocol. It is used to identify a common set of methods for the group of classes that implement the interface. It is also used to share constants between classes. Interfaces are used to provide the benefits of multiple inheritance without its implementation difficulties. They allow several classes to share a standard set of methods and constants without requiring these methods and constants to be implemented by a common superclass.

Interfaces provide a standard framework for accessing classes. They are analogous to the interfaces that we encounter in everyday life. Any large class of real-world objects that you regularly manipulate usually has a standard interface. Radios and televisions provide a common set of controls for tuning channels and adjusting audio volume. Cars come with a standard interface for steering, throttling, and braking. Automated bank tellers provide the same general interface for performing bank transactions.

To realize the potential use of Java interfaces, consider the diversity of objects that are manipulated by GUI-building programs. Such programs provide the capability to generate graphical user interfaces by clicking on interface controls and dragging them to appropriate places on the windows and dialog boxes being developed. The objects implementing these controls may support many different sets of methods. For example, one subset of the controls may be required to support cut, copy, and paste operations. These methods might be grouped into an EditObject interface. Another subset of the interface controls may be required to support click and double-click operations. These objects might implement a Clickable interface. Another subset may support drag-and-drop operations and implement the Draggable interface. Other groups of objects may implement multiple interfaces. For example, there might be objects that are both Clickable and Draggable.

The Benefits of Interfaces

Interfaces provide many advantages to the Java programmer. One is that they allow standard sets of methods to be used across the class hierarchy. For example, you can define the Editable interface to support cut, copy, and paste operations. The Editable interface can then be implemented by relevant classes and establish a uniform approach to implementing these common operations.

Interface types allow objects to be referenced by the methods they support without considering their location in the class hierarchy. They make maximal use of dynamic binding, allowing objects to be accessed independently of their implementation details. For example, parameters can be defined as interface types and used by methods. These methods can invoke the interface methods of their arguments without having to determine the classes to which the arguments belong.

Interfaces also support selective multiple inheritance. They allow various subsets of the features supported by different classes to be shared without mandating that all features of these classes be uniformly imposed as the result of inheritance.

Finally, because interfaces are declared independently of classes, they are unaffected by changes to specific classes or to the class hierarchy as a whole.

Declaring Interfaces

Interfaces, like classes, are not objects, but type definitions that can be used to declare an object. Interfaces are declared as follows:

InterfaceModifiers interface InterfaceName ExtendsClause InterfaceBody

The allowed interface modifiers are abstract and public. By default, all interfaces are abstract. The public access specifier allows interfaces to be accessed outside of the package in which they are declared, in the same manner as with classes. Only one class or interface may be declared public in a given compilation unit. The compilation unit must have the same name as its public interface or class. The extends clause is similar to the class extends clause and is covered later in this chapter.

The body of an interface begins with an opening brace ({), consists of zero or more variable or method declarations, and ends with a closing brace (}).

All variables declared in an interface body are assumed to be both static and final, must have a constant initializer, and are implemented as constant class variables.

All methods declared in an interface body are assumed to be abstract and do not have method bodies. Only access methods can be declared within an interface; constructors are not allowed. The access specifier of a method is that of the interface in which it is declared.

An example of a simple interface declaration is as follows:

public interface Clickable {
 void click();
 void doubleClick();
}

This Clickable interface is declared as public so that it can be accessed outside its package. It contains two method declarations, click() and doubleClick(). These methods must be supported by all classes that implement the Clickable interface.

Implementing Interfaces

The interfaces implemented by a class are identified in the implements clause of the class declaration. For example, the following class implements the Scrollable and Clickable interfaces:

class ExampleClass implements Scrollable, Clickable {
}

A non-abstract class must implement all interface methods that are not implemented by its superclasses. abstract classes are not required to implement interface methods. They can defer interface implementation to their non-abstract subclasses.

The CDrawApp Interface Example

To provide a concrete example of the use of interfaces, we'll extend the CDrawApp program, introduced in Chapter 5, "Classes and Objects," to include support for editable objects. Editable objects are objects that display text on the grid and can be edited using the CGTextEdit interface. The CGText class will be modified to support this interface. The CGPoint and CGBox classes will be extended by the subclasses, CGTextPoint and CGTextBox, both of which provide the capability to display text on the grid. The CGText, CGTextPoint, and CGTextBox classes will implement the CGTextEdit interface. Figure 6.1 shows the extensions to the Chapter 5 class hierarchy that were made to support this example.

Figure 6.1 : Extensions to the CDrawApp class hierarchy.

Before going on to edit and compile the source code files for this example, be sure to create a ch06 subdirectory under c:\java\jdg. This subdirectory should be used to store all the source Java files that you develop in this chapter.

The CGTextEdit Interface

The CGTextEdit interface is quite simple. Its source code is shown in Listing 6.1.


Listing 6.1. The CGTextEdit interface source code.

package jdg.ch06;

public interface CGTextEdit {
 public void replaceText(String s);
 public void upperCase();
 public void lowerCase();
}


The CGTextEdit interface source code declares three methods: replaceText(), upperCase(), and lowerCase(). These methods must be provided by all classes that implement the CGTextEdit interface. The replaceString() method is used to replace the text associated with an object with the text contained in the String's parameter. The upperCase() and lowerCase() methods are used to convert the text associated with an object to upper- and lowercase, respectively. CGTextEdit and all its interfaces are declared as public, allowing them to be accessed outside of the jdg.ch06 package. The public modifiers used with the method declarations are redundant. Any method declared in a public interface is public, by default.

After you have entered the CGTextEdit interface into the file, CGTextEdit.java, use javac to compile CGTextEdit.java. Do this from within the ch06 directory.

Updating the CGText Class

The CGText class, developed in Chapter 5, will be updated to implement the CGTextEdit interface. The easiest way to do this is to copy CGText.java from the c:\java\jdg\ch05 directory to the c:\java\jdg\ch06 directory and then edit it. Its source code is shown in Listing 6.2.


Listing 6.2. The CGText class source code.

package jdg.ch06;

import jdg.ch05.CGObject;
import jdg.ch05.Point;
import jdg.ch05.PrintCGrid;
import java.lang.System;

// CGText.java

public class CGText extends CGObject implements CGTextEdit {
 // Variable declarations
 String text;

 // Method declarations
 public CGText(Point p,String s) {
  location = p;
  drawCharacter = ' ';
  text = s;
 }
 public void display(PrintCGrid grid) {
  Point p = new Point(location);
  for(int i=0;i<text.length();++i){
   grid.putCharAt(text.charAt(i),p);
   p = p.add(1,0);
  }
 }
 public void describe() {
  System.out.println("CGText "+location.toString()+" "+text);
 }
 public void replaceText(String s) {
  text=s;
 }
 public void upperCase() {
  text = text.toUpperCase();
 }
 public void lowerCase() {
  text = text.toLowerCase();
 }
}


All you need to do is to change the package statement, add the import statements, edit the class declaration, and add the last three methods that implement the CGTextEdit interface.

Because this class is contained in the jdg.ch06 package, you need to import the CGObject, Point, and PrintCGrid classes from the jdg.ch05 package.

The class declaration is changed to add the implements clause with the CGTextEdit interface.

The three new methods are all very simple. The replaceText() method assigns text to the new value passed by the s parameter. The upperCase() and lowerCase() methods use the toUpperCase() and toLowerCase() methods of the String class to perform their conversions.

You should compile the new CGText.java before moving on to the next class.

The CGTextPoint Class

The CGTextPoint class extends the CGPoint class to add the capability to display text along with the character point. (See Listing 6.3.)


Listing 6.3. The CGTextPoint class source code.

package jdg.ch06;

import jdg.ch05.Point;
import jdg.ch05.CGPoint;
import jdg.ch05.PrintCGrid;
import java.lang.System;

// CGTextPoint.java

public class CGTextPoint extends CGPoint implements CGTextEdit {
 // Variable declarations
 String text;

 // Method declarations
 public CGTextPoint(Point p,char ch,String s) {
  super(p,ch);
  text = s;
 }
 public CGTextPoint(Point p,String s) {
  super(p);
  text = s;
 }
 public CGTextPoint(Point p,char ch) {
  super(p,ch);
  text = "";
 }
 public CGTextPoint(Point p) {
  super(p);
  text = "";
 }
 public void display(PrintCGrid grid) {
  super.display(grid);
  Point p = location.add(1,0);
  for(int i=0;i<text.length();++i){
   grid.putCharAt(text.charAt(i),p);
   p = p.add(1,0);
  }
 }
 public void describe() {
  System.out.print("CGTextPoint "+String.valueOf(drawCharacter)+" ");
  System.out.println(location.toString()+" "+text);
 }
 public void replaceText(String s) {
  text=s;
 }
 public void upperCase() {
  text = text.toUpperCase();
 }
 public void lowerCase() {
  text = text.toLowerCase();
 }
}


CGTextPoint declares the variable text. This variable is used to store the text associated with the point. It provides four constructors, each of which uses the super() constructor call statement to invoke the constructors of the CGPoint class. The four constructors allow CGTextPoint to be constructed using different combinations of parameters.

The display() method invokes the display() method of its superclass to display the point at its location on the grid. It then displays the value of the text variable to the immediate right of this point. The describe() method displays a description of the text point on the console window. The replaceText(), upperCase(), and lowerCase() methods are the same as those of the new CGText class.

The CGTextBox Class

The CGTextBox class extends the CGBox class to add the capability to display text within a box. (See Listing 6.4.) The size of the box is automatically fitted to the size of the text to be displayed.


Listing 6.4. The CGTextBox class source code.

package jdg.ch06;

import jdg.ch05.Point;
import jdg.ch05.CGBox;
import jdg.ch05.PrintCGrid;
import java.lang.System;

// CGTextBox.java

public class CGTextBox extends CGBox implements CGTextEdit {
 // Variable declarations
 String text;

 // Method declarations
 public CGTextBox(Point ulCorner, char ch, String s) {
  super(ulCorner,ulCorner.add(s.length()+1,2),ch);
  text = s;
 }
 public CGTextBox(Point ulCorner, String s) {
  super(ulCorner,ulCorner.add(s.length()+1,2));
  text = s;
 }
 public void display(PrintCGrid grid) {
  super.display(grid);
  Point p = location.add(1,1);
  for(int i=0;i<text.length();++i){
   grid.putCharAt(text.charAt(i),p);
   p = p.add(1,0);
  }
 }
 public void describe() {
  System.out.print("CGTextBox "+String.valueOf(drawCharacter)+" ");
  System.out.println(location.toString()+" "+lr.toString()+" "+text);
 }
 public void replaceText(String s) {
  text=s;
  lr=location.add(text.length()+1,2);
 }
 public void upperCase() {
  text = text.toUpperCase();
 }
 public void lowerCase() {
  text = text.toLowerCase();
 }
}


The CGTextBox class source code defines the text variable in the same manner as the CGTextPoint class and provides two constructors for initializing objects of its class. Both constructors use calls to the CGBox class to support the initialization. The parameters to these calls calculate the lower-right corner of the box using the upper-left corner as a reference point and adding horizontal and vertical offsets that size the box based on the length of the text it contains.

The display() method displays a box using the display() method of its parent. It then displays text within the box. The describe() method prints a box's parameters on the console window.

The upperCase() and lowerCase() methods are the same as those of the CGTextPoint class, but the replaceText() method is different. It updates the lr variable to correctly resize the box based on changes to the length of the text variable.

Updating the CDraw Class

The CDraw class is updated to support the Edit Text command. This requires changes to all its access methods except the addText() method. The source code of the CDrawApp and CDraw classes is shown in Listing 6.5.


Listing 6.5. The CDrawApp and CDraw classes.

package jdg.ch06;

import jdg.ch05.Point;
import jdg.ch05.CGrid;
import jdg.ch05.PrintCGrid;
import jdg.ch05.BorderedPrintCGrid;
import jdg.ch05.CGObject;
import jdg.ch05.CGPoint;
import jdg.ch05.CGBox;
import jdg.ch05.KeyboardInput;
import java.lang.System;
import java.lang.ClassCastException;
import java.io.IOException;

class CDrawApp {
 public static void main(String args[]) throws IOException {
  CDraw program = new CDraw();
  program.run();
 }
}

class CDraw {
 // Variable declarations
 static KeyboardInput kbd = new KeyboardInput(System.in);
 BorderedPrintCGrid grid;

 // Method declarations
 CDraw() {
  grid = new BorderedPrintCGrid();
 }
 void run() throws IOException {
  boolean finished = false;
  do {
   char command = getCommand();
   switch(command){
    case 'P':
     addPoint();
     System.out.println();
     break;
    case 'B':
     addBox();
     System.out.println();
     break;
    case 'T':
     addText();
     System.out.println();
     break;
    case 'U':
     grid.deleteLastObject();
     System.out.println();
     break;
    case 'C':
     grid.clearGrid();
     System.out.println();
     break;
    case 'S':
     grid.show();
     break;
   case 'E':
    editText();
    break;
   case 'X':
    finished = true;
    default:
     System.out.println();
   }
  } while (!finished);
 }
 char getCommand() throws IOException {
  System.out.print("CDrawApp P - Add a Point U - Undo Last Add");
  System.out.println(" E - Edit Text");
  System.out.print("Main Menu B - Add a Box C - Clear Grid");
  System.out.println(" X - Exit CDrawApp");
  System.out.print(" T - Add Text S - Show Grid");
  System.out.print(" Enter command: ");
  System.out.flush();
  return Character.toUpperCase(kbd.getChar());
 }
 void addPoint() throws IOException {
  System.out.println("Add Point Menu");
  System.out.println(" Location:");
  Point p = kbd.getPoint();
  System.out.print(" Character: ");
  System.out.flush();
  char ch = kbd.getChar();
  if(ch==' ') ch = '+';
  System.out.print(" Add text (y/n): ");
  System.out.flush();
  if('Y'==Character.toUpperCase(kbd.getChar())) {
   System.out.print(" Text: ");
   System.out.flush();
   String s = kbd.getText();
   CGTextPoint cgtp = new CGTextPoint(p,ch,s);
   cgtp.addToGrid(grid);
  }else{
   CGPoint cgp = new CGPoint(p,ch);
   cgp.addToGrid(grid);
  }
 }
 void addBox() throws IOException {
  System.out.println("Add Box Menu");
  System.out.println(" Upper Left Corner:");
  Point ul = kbd.getPoint();
  System.out.print(" Add text (y/n): ");
  System.out.flush();
  if('Y'==Character.toUpperCase(kbd.getChar())) {
   System.out.print(" Text: ");
   System.out.flush();
   String s = kbd.getText();
   System.out.print(" Character: ");
   System.out.flush();
   char ch = kbd.getChar();
   if(ch==' ') ch = '#';
   CGTextBox cgtb = new CGTextBox(ul,ch,s);
   cgtb.addToGrid(grid);
  }else{
   System.out.println(" Lower Right Corner:");
   Point lr = kbd.getPoint();
   System.out.print(" Character: ");
   System.out.flush();
   char ch = kbd.getChar();
   if(ch==' ') ch = '#';
   CGBox box = new CGBox(ul,lr,ch);
   box.addToGrid(grid);
  }
 }
 void addText() throws IOException {
  System.out.println("Add Text Menu");
  System.out.println(" Location:");
  Point p = kbd.getPoint();
  System.out.print(" Text: ");
  System.out.flush();
  String text = kbd.getText();
  CGText cgt = new CGText(p,text);
  cgt.addToGrid(grid);
 }
 void editText() throws IOException {
  System.out.println("Current Objects:");
  int numObjects = grid.getNumObjects();
  for(int i=0;i<numObjects;++i){
   System.out.print(" "+String.valueOf(i)+" ");
   grid.getObject(i).describe();
  }
  if(numObjects > 0){
   System.out.print("Select an object to edit: ");
   System.out.flush();
   int objIndex = kbd.getInt();
   CGObject obj = grid.getObject(objIndex);
   try {
    editText((CGTextEdit) obj);
   }catch (ClassCastException ex){
    System.out.println("Object is not editable.");
   }
  }else System.out.println("(none)");
  System.out.println();
 }
 void editText(CGTextEdit obj) throws IOException {
  System.out.println("Text Edit Menu");
  System.out.println(" R - Replace Text");
  System.out.println(" L - Lower Case");
  System.out.println(" U - Upper Case");
  System.out.print("Enter command: ");
  System.out.flush();
  char ch = kbd.getChar();
  ch = Character.toUpperCase(ch);
  switch(ch) {
   case 'R':
    System.out.print("Enter new text: ");
    System.out.flush();
    String s = kbd.getText();
    obj.replaceText(s);
    break;
   case 'L':
    obj.lowerCase();
    break;
   case 'U':
    obj.upperCase();
    break;
  }
 }
}


The run(), getCommand(), addPoint(), and addBox() methods are updated to support the Edit Text command. The two overloaded editText() methods are added to process this command.

The switch statement of the run() method adds the 'E' case to its list of command options, calling the editText() method to process the Edit Text command. The getCommand() method adds the Edit Text command to its menu display.

The addPoint() and addBox() methods query the user to determine whether text should be added to the point or box. If the user declines to add text, a CGPoint or CGBox object is created and added to the grid. If the user indicates that he or she wants to add text to the point or box, the user is prompted to enter the text. In this case, CGTextPoint and CGTextBox objects are created and added to the grid.

The two editText() methods share the same name but provide completely different processing. The first editText() method is invoked when the user enters the Edit Text command. It displays a list of the objects that are currently added to the grid. It does this by using the getNumObjects() method of the PrintCGrid class to find out how many objects there are and then retrieving those objects using the getObject() method of the PrintCGrid class. The following line of code concatenates two method invocations:

grid.getObject(i).describe();

It retrieves an object of class CGObject by invoking the getObject() method of the PrintCGrid class. It then invokes the object's describe() method so that it will display its description on the console window. If there are no objects currently added to the grid, the editText() method indicates this fact by displaying (none) to the console window. Otherwise, the user is prompted to enter the number of the object to edit. This number is the number listed in the current object display. The number entered by the user is used to retrieve the object to be edited using the getObject() method. After the object is retrieved, the editText() method tries to edit the text associated with the object by invoking the second editText() method. If the object does not implement the CGTextEdit interface, a ClassCastException is thrown during the invocation of the second editText() method. The first editText() method catches this exception and reports the selected object as not being editable.

The second editText() method displays a Text Edit Menu prompt to the user and invokes the replaceText(), lowerCase(), and upperCase() methods to process the commands entered by the user.

Running the Example

The CDrawApp program is compiled and executed in the same manner as its Chapter 5 predecessor. You should notice the additional Edit Text command provided in the CDrawApp main menu:

C:\java\jdg\ch06>java jdg.ch06.CDrawApp
CDrawApp    P - Add a Point   U - Undo Last Add   E - Edit Text
Main Menu   B - Add a Box     C - Clear Grid      X - Exit CDrawApp
            T - Add Text      S - Show Grid       Enter command:

We'll add a few objects to the grid, display them, and then edit their text. After you learn how to use the new program, we'll discuss its features as they relate to interfaces.

Enter P to add a point to the grid. Set its x-coordinate to 60, its y-coordinate to 10, and its draw character to @:

Add Point Menu
 Location:
  x-coordinate: 60
  y-coordinate: 10
 Character: @
 Add text (y/n):

You are asked whether you want to add text to the point. Press Y to add text. You are then prompted to add your text. Enter at sign as your text, as shown in the following display output:

Add Point Menu
 Location:
  x-coordinate: 60
  y-coordinate: 10
 Character: @
 Add text (y/n): y
  Text: at sign

The CDrawApp main menu is then redisplayed. Enter B to add a box. Set the box's upper-left corner as follows:

Add Box Menu
 Upper Left Corner:
  x-coordinate: 4
  y-coordinate: 4
 Add text (y/n):

Enter Y to add text to the box. You are prompted to enter your text. Enter the text Java's interfaces support multiple inheritance.. Then set the box's draw character to +. Your display output should look like the following:

Add Box Menu
 Upper Left Corner:
  x-coordinate: 4
  y-coordinate: 4
 Add text (y/n): y
  Text: Java's interfaces support multiple inheritance.
 Character: +

Enter B to enter another box. This box will not contain any text. Enter the coordinates for the box's corners, as follows:

Add Box Menu
 Upper Left Corner:
  x-coordinate: 65
  y-coordinate: 15
 Add text (y/n): n
 Lower Right Corner:
  x-coordinate: 72
  y-coordinate: 18

Then set its draw character to a hyphen:

Character: -

You should have noticed that when a box contains text, its lower-right corner is not specified. That's because the program computes it based on the length of the text to be displayed with the box.

You're almost done adding objects to the grid. Enter T to add text to the grid. Set the text's location and value as follows:

Add Text Menu
 Location:
  x-coordinate: 1
  y-coordinate: 18
 Text: UPPER CASE Or lower case

You now have enough objects to work with. Enter S to display the grid. It should look like this:

***************************************************************************
*                                          &nb sp;                                *
*                                          &nb sp;                                *
*                                          &nb sp;                                *
*                                          &nb sp;                                *
*    +++++++++++++++++++++++++++++++++++++++++++++++++                      *
*    +Java's interfaces support multiple inheritance.+                      *
*    +++++++++++++++++++++++++++++++++++++++++++++++++                      *
*                                          &nb sp;                                *
*                                          &nb sp;                                *
*                                          &nb sp;                                *
*                                          &nb sp;                 @ at sign      *
*                                          &nb sp;                                *
*                                          &nb sp;                                *
*                                          &nb sp;                                *
*                                          &nb sp;                                *
*                                          &nb sp;                      --------  *
*                                          &nb sp;                      -      -  *
*                                          &nb sp;                      -      -  *
* UPPER CASE Or lower case                                  & nbsp;     --------  *
*                                          &nb sp;                                *
***************************************************************************

Let's start editing these objects. Enter E to select an object to edit:

CDrawApp    P - Add a Point   U - Undo Last Add   E - Edit Text
Main Menu   B - Add a Box     C - Clear Grid      X - Exit CDrawApp
            T - Add Text      S - Show Grid       Enter command: e

Current Objects:
 0 CGTextPoint @ (60,10) at sign
 1 CGTextBox + (4,4) (52,6) Java's interfaces support multiple inheritance.
 2 CGBox - (65,15) (72,18)
 3 CGText (1,18) UPPER CASE Or lower case

Select an object to edit:

A list of the grid's current objects is displayed. Enter 2 to select the object of class CGBox. Because this object does not implement the CGTextEdit interface, it is identified as not being editable, as shown in the following console output:

Object is not editable.

See if you can find where this processing was performed within the CDraw class. Enter E again to edit another object. The list of current objects is again displayed. Enter 1 to select the object of class CGTextBox. The Text Edit Menu prompt is displayed as follows:

Text Edit Menu
 R - Replace Text
 L - Lower Case
 U - Upper Case
Enter command:

This menu allows you to use the methods of the CGTextEdit interface to edit the objects that implement the interface. Enter R to replace the text associated with the CGTextBox object. You are then prompted to enter the new text for this object. Enter interfaces to complete the editing. Your display should contain the following output:

Enter command: r
Enter new text: interfaces

Enter S to see how the grid was updated. Notice how the size of the CGTextBox was changed to fit the size of the text it contains:

++++++++++++
+interfaces+
++++++++++++

Enter E and then 0 to edit the object of class CGTextPoint. Then type U to change it to uppercase. Use the show command to verify that the text has been changed to uppercase.

Enter E, 3, and L in succession to change the case of the text contained in the CGText object. Use the Show Grid command to redisplay the grid:

***************************************************************************
*                                          &nb sp;                                *
*                                          &nb sp;                                *
*                                          &nb sp;                                *
*                                          &nb sp;                                *
*    ++++++++++++                                    &nb sp;                      *
*    +interfaces+                                    &nb sp;                      *
*    ++++++++++++                                    &nb sp;                      *
*                                          &nb sp;                                *
*                                          &nb sp;                                *
*                                          &nb sp;                                *
*                                          &nb sp;                 @ AT SIGN      *
*                                          &nb sp;                                *
*                                          &nb sp;                                *
*                                          &nb sp;                                *
*                                          &nb sp;                                *
*                                          &nb sp;                      --------  *
*                                          &nb sp;                      -      -  *
*                                          &nb sp;                      -      -  *
* upper case or lower case                                  & nbsp;     --------  *
*                                          &nb sp;                                *
***************************************************************************

Now type X to exit the CDrawApp program.

Example Summary

The CDrawApp program illustrates the use of a simple interface. The CGTextEdit interface, used in this example, provides a common set of access methods to three classes on different branches of the CDrawApp class hierarchy, as shown in Figure 6.2.

Figure 6.2 : The interface.

Providing a standard interface to the CGText, CGTextPoint, and CGTextBox classes makes it possible to manipulate objects of these classes as if they belong to a single type. This is illustrated in the second editText() method of the CDraw class. This method takes an object of the CGTextEdit interface type as an argument and edits that object without having to know to which class the object belongs. Although the methods of the CGTextEdit interface are very simple, the capability provided by the interface is not. The second editText() method is able to manipulate any object that implements the CGTextEdit interface, even those that may be defined in the future.

The first editText() method of the CDraw class also provides an interesting example of the use of interfaces. The first part of the method displays the list of current objects, one of which is selected by the user. The try statement tests to see if the selected object implements the CGTextEdit interface by trying to cast it to an object of interface type CGTextEdit. The casting is performed when the object is used as an argument to the second editText() method:

try {
 editText((CGTextEdit) obj);
}catch (ClassCastException ex){
 System.out.println("Object is not editable.");
}

Casting is the process of changing the type by which an object is accessed. It is covered in Chapter 11, "Language Summary." An object can be cast to an interface type if the object implements the interface; otherwise, a ClassCastException is thrown.

The editText() method uses casting to determine whether an object implements the CGTextEdit interface. If the object implements the CGTextEdit interface, the casting is allowed and the second editText() method is invoked to edit the object. If the object does not implement the CGTextEdit interface, an exception is thrown. This exception is caught by the catch part of the try statement and the object is identified as not editable.

Using Interfaces as Abstract Types

The preceding example shows how interfaces can be used to declare method parameters. Such declarations require only that the objects passed as arguments during a method invocation implement the identified interface.

In the following example, the restart() method of ExampleClass declares the currentSelection parameter to be of type ExampleInterface. The restart() method has no idea what class of object is passed to it via currentSelection. It only requires it to implement the ExampleInterface. The fact that the correct methods are called for the object identified by currentSelection is an example of polymorphism. The code for ExampleInterface follows:

interface ExampleInterface {
    void rewind();
    void play();
    void stop();
}
class ExampleClass {
    void restart(ExampleInterface currentSelection) {
         currentSelection.stop();
         currentSelection.rewind();
         currentSelection.play();
    }
}

The restart() method uses the ExampleInterface methods of the currentSelection object to perform its processing. Note that ExampleClass does not need to implement ExampleInterface. The interface only needs to be implemented by the object passed via the currentSelection parameter.

Interface Constants

The variables declared in an interface body are available as constants to classes that implement the interface. This enables pools of related constants to be defined and made available to classes that require use of these constants. Common constant pools are color constants, mathematical constants, and formatting constants. Variables declared in an interface are implicitly static and final and must be initialized in their declaration.

The following example shows how interface variables are used to define a constant pool. Create a file in your ch06 directory called ColorConstants.java and enter the code shown in Listing 6.6.


Listing 6.6. The ColorConstants interface defines red, blue, and green constants.

package jdg.ch06;

public interface ColorConstants {
 int red = 0xff0000;
 int green = 0xff00;
 int blue = 0xff;


Compile this code using javac. Then create another file called ColorTestApp.java, as shown in Listing 6.7.


Listing 6.7. The ColorTestApp class source code.

package jdg.ch06;

import java.lang.System;

class ColorTestApp implements ColorConstants {
 public static void main(String args[]) {
  System.out.println(red);
  System.out.println(green);
  System.out.println(blue);
 }
}


Compile ColorTestApp.java and execute it using java. Your console window should display the following output:

C:\java\jdg\ch06>java jdg.ch06.ColorTestApp
16711680
65280
255

The main() method of the ColorTestApp class is able to access the constants defined in the ColorConstants interface as if they were inherited variables. The main() function displays these hexadecimal constants as decimal integers.

Extending Interfaces

The interface extends clause is similar to the extends clause used with classes. An interface is allowed to extend more than one interface, but a class can extend only a single class. The extending interface inherits all the methods and constants defined in the interfaces that it extends. When a class implements an interface X, it must implement all methods of all interfaces that X extends.

The following example declares the MoreTextEdit interface as extending the CGTextEdit interface. All classes that implement the MoreTextEdit interface must implement the methods of both CGTextEdit and MoreTextEdit:

interface MoreTextEdit extends CGTextEdit {
 void insertText(int pos, String s);
 void appendText(String s);
}

Combining Interfaces

Two or more interfaces may be combined into a single interface through extension. The following example shows how interfaces are combined:

interface TV {
 void changeChannel(int channelNumber);
 void changeVolume(int volumeSetting);
}
interface VCR {
 void play();
 void rewind();
 void record();
}
interface TVCR extends TV, VCR {
}

Any non-abstract class that implements the TVCR interface is required to implement the methods of the TV interface and the VCR interface.

Summary

In this chapter you have learned how to use Java interfaces to provide a common set of methods by which a group of classes can be accessed. You have added the CGTextEdit interface to the CDrawApp example from Chapter 5 and learned how to declare objects using interface types. You have also learned how to use interface constants. In Chapter 7, "Exceptions," you'll learn how to use Java exceptions to perform error processing.