As discussed earlier, Java does not allow a class to inherit more
than one class as in C++. That is,
class
Test extends aClass, bClass{ // Error !!
There are situations where multiple inheritance can be useful but
it can also lead to problems. For example, a reference to a method
with the same name in both classes needs a system for making it
explicit as to which class should be used.
Iinterfaces provide most of the advantages of multiple inheritance
with fewer problems. An interface is basically an abstract
class but with all
of the methods abstract. (The methods in an
interface do not need the explicit abstract
modifier since they are abstract by definition.)
A class implements
an interface rather than extends it. Any class that implements
the interface must override all the interface methods with it's
own methods.
(In the case of identical method names in two interfaces, it's
irrelevant since both methods are abstract and carry no code body.
In a sense, both are overridden by the single method of that name
in the implementing class.)
In the example below, Runnable
is an interface with a single method: run().
So any method that implements Runnable
must override run().
class
Test extends Applet implements
Runnable
{
...
public
void
run
() {
...
}
}
interface
Runnable
{
public
void
run
();
}
|
Any number of interfaces can be implemented. Just
separate the interface names with a comma:
class
Test extends Applet implements
Runnable,
AnInterface
{
...
public
void
run
() {
...
}
...
public
void
walk
() {
...
}
}
interface
AnInterface
{
public
void
walk
();
}
|
Any class that implements an interface can be referenced
as a type of that interface, as shown in this code:
class
Test extends Applet
{
public
void init () {
Runnable r;
r = new
user();
...
...
}
}
class
User implements
Runnable
{
public
void run () {
...
}
}
|
Note: Interface
names often end with "able"
to imply that they add to the capabilty of the class.
Interfacing Classes
Interface is a very suitable name because they provide a systematic
way of providing an entrance to a class. That is, they provide a
common interface.
Suppose we have classes Relay
and Valve
that are completely independent, perhaps written by two different
people. If we want he class Test
to communicate with these classes, an interface provides a simple,
standard way to do this.
Lets define an interface called Switchable,
which holds a single method called getState(),
as in
public
interface Switchable
{
public boolean getState();
}
We want to use getState()
to return a value that indicates whether a relay or a valve is on
or off. In the code below we show the class Test
that casts instances of Relay and Valve as Switchable
types and it can then call their respective getState()
to communicate with them:
public
class
Test
{
public static void
main(String [] args)
{
Switchable
[] state = new Switchable[2];
state[0] = new Relay ();
state[1] = new Valve ();
for (int
i=0; i < 2; i++)
{
if
(state[i].getState ()) sum++;
}
}
... other code ...
}
class
Relay implements Switchable
{
boolean setting = false;
//
Override the interface method
boolean
getState ()
{
return
setting;
}
...
other code ...
}
class
Valve implements Switchable
{
boolean open = false;
//
Override the interface method
boolean
getState
()
{
return
open;
}
...
other code ...
}
interface
Switchable
{
void
getState ();
}
|
So the only modifications required for the classes
Relay
and Valve
were the implementation of the interface Switchable.
We override the getState()
with code appropriate to the task for the particular class.
In the class Test
we illustrate how we can treat instances of Relay
and Valve
as a common type of Switchable
and use the getState()
to find the desired info for the particular class.
If later we want to find the state from a Pump
or other class that represents a device of interest, we just tell
the author to implement the Switchable
interface. So we see that an interface can serve literally to interface
otherwise incompatible classes together.
Interfaces
for Callbacks
A common technique in the C language is to pass a
pointer to a function in the argument list of another function.
The receiving function can invoke the passed function using the
pointer. This approach is referred to as a callback.
Callbacks are very useful in situations where you
want to invoke different functions without needing to know what
particular function is being invoked. For example, a plotting function
could receive a pointer to a function that takes a value on the
horizontal axis as an argument and returns a value for the vertical
axis. The plotting function could then plot any such function that
is passed to it.
Java, however, does not provide for pointers (direct
memory addresses) to methods. Instead, interfaces are used for callbacks.
In this case, a method holds an interface reference in its argument
list and then invokes a method in the interface.
(The Method
class in the Reflection
package can represent a method and can invoke it in a general manner.
However, it is not recommended to use Method
for callbacks. It is rather clumsy and it also loses the type checking
on the arguments and return type during the compilation.)
In the following code, we see that the
aFunc(Switchable obj) method invokes
the getState()
method of the Switchable
interface. An instance of any class that implements the Switchable
interface can be passed, thus providing the same generality as the
pointer callbacks in C.
public
class
TestCallBack
{
public static void
main(String [] args)
{
Switchable
[] switches = new Switchable[3];
switches[0] = new Relay
();
switches[1] = new Relay
();
switches[2] = new Valve
();;
for
(int i=0; i < 3; i++)
{
aFunc (switches[i]);
}
}
// Pass Switchable objects
and call their getState()
void aFunc (Switchable obj)
{
if (obj.getState
()) doSomething ();
}
... other code...
}
See previous example for the Switchable,
Relay, & Valve definitions.
|
More
about Interfaces
An interface can also contain data fields but they must be declared
static and
final, where
final
indicates that the data cannot be modified. (See Chapter
5: Interfaces with Only Constants.)
An interface can extend another interface and thus inherit the
abstract methods and final, static data of the super-interface.
We will discuss access rules and modifiers in the next chapter
but here we will note that interface methods are public.
(So the overriding methods in the classes that implement the interface
must also be public.)
An interface can be empty. That is, an interface could contain
no methods or data at all. Such an empty interface can be useful
as a "marker" of classes. That is, you can use the instanceof
operator to determine if a class is of the particular marker type,
which then can imply some quality of the class. We will see later,
for example, that one can use the empty cloneable
interface to indicate whether a class overrides the clone
method from Object
for making copies of the class.
Last update: Oct. 23, 2004
|