Tuesday, November 11, 2008

Accessing Implementations through Interface References

Accessing Implementations through Interface References:

 

You can declare variables as object references that use an interface rather than a class type. Any instance of any class that implements the declared interface can be referred to by such a variable. When you call a method through one of these references, the correct version will be called based on the actual instance of the interface being referred to. This is one of the key features of interfaces. The method to be executed is looked up dynamically at run time, allowing classes to be created later than the code which calls methods on them. The calling code can dispatch through an interface without having to know anything about the "callee." This process is similar to using a superclass reference to access a subclass object, as described in Previous Post.

 

Because dynamic lookup of a method at run time incurs a significant overhead when compared with the normal method invocation in Java, you should be careful not to use interfaces casually in performance-critical code.

 

The following example calls the callback( ) method via an interface reference variable:

 

class TestIface {

public static void main(String args[]) {

Callback c = new Client();

c.callback(42);

}

}

 

The output of this program is shown here:

 

callback called with 42

 

Notice that variable c is declared to be of the interface type Callback, yet it was assigned an instance of Client. Although c can be used to access the callback( ) method, it cannot access any other members of the Client class. An interface reference variable only has knowledge of the methods declared by its interface declaration. Thus, c could not be used to access nonIfaceMeth( ) since it is defined by Client but not Callback.

 

While the preceding example shows, mechanically, how an interface reference variable can access an implementation object, it does not demonstrate the polymorphic power of such a reference. To sample this usage, first create the second implementation of Callback, shown here:

 

// Another implementation of Callback.

class AnotherClient implements Callback {

// Implement Callback's interface

public void callback(int p) {

System.out.println("Another version of callback");

System.out.println("p squared is " + (p*p));

}

}

Now, try the following class:

class TestIface2 {

public static void main(String args[]) {

Callback c = new Client();

AnotherClient ob = new AnotherClient();

c.callback(42);

c = ob; // c now refers to AnotherClient object

c.callback(42);

}

}

 

The output from this program is shown here:

 

callback called with 42

Another version of callback

p squared is 1764

 

As you can see, the version of callback( ) that is called is determined by the type of object that c refers to at run time. While this is a very simple example, you will see another, more practical one shortly.

 

Partial Implementations

If a class includes an interface but does not fully implement the methods defined by that interface, then that class must be declared as abstract.

 

For example:

 

abstract class Incomplete implements Callback {

int a, b;

void show() {

System.out.println(a + " " + b);

}

// ...

}

 

Here, the class Incomplete does not implement callback( ) and must be declared as abstract. Any class that inherits Incomplete must implement callback( ) or be declared abstract itself.

No comments: