Chapter 10: Interfaces


The previous chapter showed you how an abstract class is a class where something is missing. This chapter will present interfaces. An interface is not actually a class, but it's like a class where nearly everything is missing.

A List of Method Declarations

An interface is mostly a list of public method declarations. The source code for an interface is similar to the source for a class in several ways. In particular, an interface definition goes in its own source file, and the source file name should be the interface name, plus .java at the end. When the code is compiled, the output file name is the interface name plus .class.

Here is an example of an interface. It should appear in source file Talker.java, and compilation will produce Talker.class:

package nature; public interface Talker {   void say(String sayThis);   void repeat(String repeatThis, int nTimes); }

This interface is in a package called nature. Like a class, an interface can belong to a package. It is designated public, so it can be used by any code anywhere. If it were not public, it could be used with the nature package only. Interfaces cannot be private or protected.

Before we proceed, it's time to say a little about the String class, which appears in the argument list of both methods (and as an array in the argument list of every main() method). This is one of many useful utility classes that come with Java. You'll learn about them in Chapter 12, "The Core Java Packages and Classes". For now, be aware that an instance of the String class encapsulates a "run" or "string" of text. The data and methods of String won't be used in this chapter.

The list of method declarations appears between the curly brackets that follow the interface name. These declarations are much like abstract method declarations. The return types, method names, and argument lists are present, but the method body is absent, replaced by a semicolon. Unlike abstract methods, the methods declared in an interface are all public. You can declare them as public explicitly if you like, but you may not declare them private or protected. Omitting the access modifier results in public, rather than default, access.

Any class can declare that it implements any interface. This declaration occurs in the class's definition file. The class name is followed by the keyword implements, followed by the interface name. For example:

package nature; class Parrot extends Bird implements Talker {   . . . } 

When a class declares that it implements an interface, the class is saying that it contains an implementation for each of the methods in the interface. (If this is not the case, the class will not compile.) So if the Parrot class compiles, you know that it contains a method called say() and another method called repeat(), with argument lists as specified in the interface.

A class is allowed to implement multiple interfaces. To do this, just provide a comma-separated list of interfaces after the implements keyword. So if Flyer and BugEater are interfaces of the nature package, you could have the following class:

package nature; class Mynah extends Bird             implements Talker, Flyer, BugEater {   . . . }

This class would have to provide implementations for the methods of all three interfaces.

Using Interfaces

To see why interfaces are useful, consider the class inheritance hierarchy shown in Figure 10.1.

click to expand
Figure 10.1: Animal kingdom class inheritance

Figure 10.1 would be a very natural way to organize your work if you were creating an extensive library of classes to model the behavior of different kinds of animals. You can imagine behavior such as live birth, cold-bloodedness, and flight being implemented by methods in the Mammal, Reptile, and Bird classes, respectively, and inherited by their respective subclasses. However, there is some behavior that does not fit into the inheritance model.

The three shaded classes in Figure 10.1 share somewhat related behavior. All three species are capable of speech, although the nature of that speech varies greatly from species to species. We humans speak out loud, and we understand what others say. Gorillas can't speak out loud because they don't have the right kind of vocal cords, but they can be taught to use and respond to sign language. (See www.gorilla.org for more information.) Parrots can speak out loud (and do so long after the charm has worn thin), but they do it without comprehension.

A good computer model of the animal kingdom should include speech, so it would make sense to give each of the Human, Gorilla, and Parrot classes its own version of the say() and repeat() methods described in the previous section. But in that case, the three classes can declare that they implement the interface. For example, Gorilla might look like this:

package nature; public class Gorilla extends Primate implements Talker {   public void say(String sayThis)   {     // Complicated code to produce sign language.   }   public void repeat(String repeatThis, int nTimes)   {     for (int i=0; i<nTimes; i++)       say(repeatThis);   }   . . . }

So far we have not mentioned any benefit associated with declaring that a class implements an interface. To understand the benefit, let's revisit the issue of objects and references.

Objects and References

You have already seen that a reference is something that uniquely identifies an object. In Java, you don't have variables that are objects. Instead, you have variables that are references to objects. In Chapter 8, "Inheritance," you saw that the type of a reference can be different from the class of the object it refers to. This point is important enough that we make a distinction between the type of a reference and the class of an object. A reference's type is what appears in the declaration of the reference variable; an object's class is the class of the constructor that was invoked when the object was created.

You have already seen that when a reference points to an object, the type of the reference can be exactly the class of the object, or it can be any superclass of the class of the object. Interfaces provide an even wider range of reference types, because reference variable types can be interfaces as well as classes. An interface-type reference can legally point to an object if that object's class implements the interface. So in our ongoing example, the following code would be perfectly legal:

Parrot polly = new Parrot(); Talker aTalker = polly;

Or even:

Talker aTalker = new Parrot();

With an interface-type reference, you can call only the methods of the interface. This may seem limiting, but the benefit is huge. Consider the following method:

singHappyBirthday(Talker t, String forWhom) {   t.repeat("Happy birthday to you.", 2);   t.say("Happy birthday, dear");   t.say(forWhom);   t.say("Happy birthday to you."); }

This method has a talker recite the song, no matter what the class of the talker. A human will sing, a gorilla will sign, a parrot will squawk. This is another example of polymorphism: A single method name (say, and also repeat) appears in many different forms.

instanceof

Java has a keyword, instanceof, that tests the relationship between an object and a reference type. The syntax is

<reference> instanceof <type>

The reference can be any reference. The type can be the name of any class or interface. The value of an instanceof expression is boolean. It is true if a reference of the given type legally can point to the object pointed to by the given reference. For example, this code will print out the message:

Duck daffy = new Duck(); if (daffy instanceof Bird) {   System.out.println("Yes, Daffy is a bird."); }

So will the following:

Bird daffy = new Duck(); if (daffy instanceof Bird) {   System.out.println("Yes, Daffy is a bird."); } 

And so will the following:

Object daffy = new Duck(); if (daffy instanceof Bird) {   System.out.println("Yes, Daffy is a bird."); }

The instanceof keyword doesn't care about the type of the variable (that is, the word that comes before instanceof. What matters is the class of the object to which the variable points, and in all three examples the class is Duck. When the second argument of instanceof is a class, as in this example, the value is true if the object's class is the same as, or a subclass of, the second argument. Here is an example of instanceof where the second argument is an interface:

Duck daffy = new Duck(); if (daffy instanceof Talker) {   System.out.println("Yes, Daffy is a bird."); }

When the second argument is an interface, the value of an instanceof expression is true if the object's class implements the interface. Here, the object's class is Duck, which does not implement Talker, so the value is false. In the following code, the value is true:

Gorilla ndume = new Gorilla(); if (ndume instanceof Talker) {   System.out.println("Yes, Ndume can talk."); }




Ground-Up Java
Ground-Up Java
ISBN: 0782141900
EAN: 2147483647
Year: 2005
Pages: 157
Authors: Philip Heller

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net