19 Mar 1996

Interfaces

An interface declares the argument types and return type associated with each member of a collection of methods. The interface definition is essentially a special type of class in which any data items are constant (public static final) and the methods contain no code (they are abstract). Other classes can then declare that they implement the interface and provide real definitions for each of the interface methods, including a body of executable statements.

In Java, a class can only extend one parent class. In practice, the world is never really that simple. In a bank, a savings account pays interest and a checking account clears checks. Then along comes a checking account that pays interest. Some Object Oriented languages allow a new class to be derived from several parent classes, but that gets to be confusing. Java accomplishes the same objective by allowing a class to extend one parent, but then implement many different interfaces.

Although it appears that the interface is designed first and then the classes come later, in real life an interface is often defined when a bunch of unrelated classes are noted to have some common operations. For example, as fault tolerance is added to an application, the programmer starts to code methods that save the essential information about an object to disk, so that it can be restored after a system crash. This operation is commonly known as a "checkpoint". Not every object can be checkpointed, and some objects don't contain information worth checkpointing. After a while, the programmer realizes that there is a common set of operations and defines an interface to describe them:

interface Checkpoint {
void take_checkpoint();
void restore_checkpoint();
};

Now all the classes that are able to checkpoint and restore their objects can be redefined as "implements Checkpoint". In the past, one would say that a program checkpoints a block of data. An Object Oriented programmer would now say that the program asks the data object to checkpoint itself. It seems like a fine distinction, but as the program gets more complicated, the OO approach turns out to be much simpler.

The system now creates a Purchase class that supports checkpointing:

class Purchase implements Checkpoint {…}

Whatever else is in the class, it must include field methods named take_checkpoint and restore_checkpoint. An object of the class is now created:

Purchase myPO = new Purchase;

The fact that Purchase extends Checkpoint is unimportant within any part of the program that understands that myPO is an object of the Purchase class. The two methods in the interface are also public methods of the Purchase class just like all the other class methods, and they don't have to be treated differently just because they happen to be part of the interface.

However, we don't want to have to create custom fault tolerant logic for every new class. Somebody has to decide if enough time has passed, or enough changes have been made, or a transaction has been committed, and a new checkpoint is needed. If its simply a matter of taking a new checkpoint every five minutes, then the code that handles the timer doesn't care that this happens to be a member of the Purchase class. It only needs to know that the object implements the Checkpoint interface.

addRecoverableObject(Checkpoint thing) {…}

In this declaration, "thing" appears to be a reference variable whose value designates an object of the Checkpoint class. However, Checkpoint isn't a class, its an interface. So the real meaning is that the parameter "thing" is a reference variable whose value can designate any class whose declaration indicates that it implements the Checkpoint interface.

The AddRecoverableObject method can be called with myPO as an argument. The methods does not know that myPO is actually a member of the Purchase class, so it cannot use instance variables or methods unique to that class. It can call the methods named take_checkpoint and restore_checkpoint. Since the actual code for these methods is provided by the Purchase class, these two methods will have access to all the fields and to features unique to a Purchase object. The function of the addRecoverableObject routine is not to do the checkpointing, but just to decide when to tell an object to checkpoint itself.

When dealing with a reference variable associated with a high level class that is the parent to many classes some of which implement an interface, the instanceof operator can be used to determine if a particular object belongs to a class that implements a specific interface.

if (x instanceof Checkpoint){((Checkpoint) x).take_checkpoint()};

Note that "(Checkpoint) x" appears to be a cast of the object designated by x to the Checkpoint class. This is another place where an interface name appears where a class name is normally used and represents "any class that implements the interface" instead of a specific class.

Continue Back PCLT

Copyright 1996 PC Lube and Tune -- Java H. Gilbert