- Special Edition Using Java, 2nd Edition -

Chapter 13

Interfaces


by Joe Weber and Mike Afergan

Interfaces are Java's substitute for C++'s feature of multiple inheritance, the practice of allowing a class to have several superclasses. While it is often desirable to have a class inherit several sets of properties, for several reasons the creators of Java decided not to allow multiple inheritance. Java classes, however, can implement several interfaces, thereby enabling you to create classes that build upon other objects without the problems created by multiple inheritance.

Somewhat resembling classes in syntax, interfaces are used when you want to define a certain functionality to be used in several classes, but are not sure exactly how this functionality will be defined by these classes. By placing such methods in an interface, you are able to outline common behavior and leave the specific implementation to the classes themselves. This makes using interfaces instead of classes a better choice when dealing with advanced data handling.

What are Interfaces?

Interfaces are the underprivileged first cousins of classes. While classes have the ability to define an object, interfaces define a set of methods and constants to be implemented by another object. From a practical viewpoint, interfaces help to define the behavior of an object by declaring a set of characteristics for the object. For example, knowing that a person is an athlete does not define their entire personality, but does ensure that they have certain traits and capabilities.

As an example, say an athlete will always have a 100 meter time, be able to perform the task of running a mile, and be able to lift weights. By later implementing the athlete interface, you ensure that a person will possess these abilities.

Thinking of interfaces in another way, take your radio, TV, and computer speakers. Each of them has one common control—volume. For this reason, you might want all these devices to implement an interface called VolumeControl.

Interfaces have one major limitation: they can define abstract methods and final fields, but cannot specify any implementation for these methods. For methods, this means that when writing a method, the body is empty. The classes that implement the interface are responsible for specifying the implementation of these methods. This means that, unlike extending a class, when you implement a method you must override every method in the interface.

In general, interfaces enable you as a programmer to define a certain set of functionality without having any idea as to how this functionality will be later defined. For example, if a class implemented the java.lang.Runnable interface, it is known to have a run() method. Because the virtual machine can be assured that any Runnable class has a run() method, the VM can blindly call the run() method. At the same time, when the designers were writing the virtual machine, they did not have to know anything about what would happen in the run() method. So, you could be doing an animation, or calculating the first 1,000 prime numbers. It doesn’t matter; all that does matter is that you will be running, and you have established that by implementing the Runnable interface.

Another excellent example is the java.applet.AppletContext interface. This interface defines a set of methods that returns information regarding the environment in which an applet is running. For instance, the AppletContext defines a method called getImage. Any viewer capable of running an applet has a means to load an image.

The problem is that different viewers such as the Appletviewer or Netscape Navigator do this differently. Worse yet, even the same browser varies based on the platform it is running on. Fortunately, every browser implements the AppletContext interface, so while the java.applet.Applet class depends on the methods declared in the AppletContext interface, it does not need to worry about how these methods work. That means, you can use the same applet class and the same methods (such as java.applet.Applet.getImage()) in a variety of environments and browsers without worrying about whether the getImage() method will be there.

Creating an Interface

The syntax for creating an interface is extremely similar to that for creating a class. However, there are a few exceptions. The most significant difference is that none of the methods in your interface may have a body, nor can you declare any variables that will not serve as constants. Nevertheless, there are some important things that you may include in an interface definition.

An example interface is shown in listing 13.1. It shows three items: an interface, a class that implements the interface, and a class that uses the derived class. Look it over to get an idea as to how interfaces are used and where we are going in this chapter. As you go on, you can thoroughly examine each portion.

Listing 13.1 An application of an interface.

public interface Product {
static final String MAKER = "My Corp";
static final String PHONE = "555-123-4567";
public int getPrice(int id);
}
public class Shoe implements Product {
public int getPrice(int id) {
if (id == 1)
return(5);
else
return(10);
}
public String getMaker() {
return(MAKER);
}
}
public class Store {
static Shoe hightop;
public static void init() {
hightop = new Shoe();
}
public static void main(String argv[]) {
init();
getInfo(hightop);
orderInfo(hightop);
}

public static void getInfo(Shoe item) {
System.out.println("This Product is made by "+ item.MAKER);
System.out.println("It costs $" + item.getPrice(1) + '\n');
}
public static void orderInfo(Product item) {
System.out.println("To order from " + item.MAKER + " call " + item.PHONE + ".");
System.out.println("Each item costs $" + item.getPrice(1));
}
}

The Declaration

Interface declarations have the syntax

public interface NameofInterface extends InterfaceList

where everything in italics is optional.

Public Interfaces

By default, interfaces may be implemented by all classes in the same package. But if you make your interface public, you allow classes and objects outside of the given package to implement it as well.

Just like public classes, public interfaces must be defined in a file named NameOfInterface.java.
 

Interface Name

The rules for an interface name are identical to those for classes. The only requirements on the name are that it begin with a letter, an underscore character, or a dollar sign; contain only Unicode characters (basic letters and digits, as well as some other special characters); and not be the same as any Java keyword (such as extends or int). Again, like classes, it is common practice to capitalize the first letter of any interface name.

See “Keywords,” Chapter 7 for more information.
 

 

While only required for public interfaces, it is a good practice to place all interfaces in a file named NameOfInterface.java. This enables both you and the Java compiler to find the source code for your class.
 
Thus, while the Product interface is not public, you should still declare it in a file named Product.java.
 

Extending Other Interfaces

In keeping with the OOP practice of inheritance, Java interfaces may also extend other interfaces as a means of building larger interfaces upon previously developed code. The new sub-interface inherits all the methods and static constants of the super-interfaces just as subclasses inherit the properties of superclasses.

See “Object Oriented Programming: A New Way of Thinking,” Chapter 6 for more information.
 

The one major rule that interfaces must obey when extending other interfaces is that they may not define the body of the parent methods, any more than they can define the body of their own methods. Any class that implements the new interface must define the body of all of the methods for both the parent and child interface.

As an example, the following lines are the declarations of two separate interface, which extends a previously defined interface (Runnable):

interface MonitoredRunnable extends java.lang.Runnable {
boolean isRunning() {
}
}

The declaration shows a more detailed Runnable interface, including some of the features that can be found in java.lang.Thread.

Interfaces cannot extend classes. There are a number of reasons for this, but probably the easiest to understand is that any class which the interface would be extending would have its method bodies defined. This violates the “prime directive” of interfaces.
 

Remember that if you implement an extended interface, you must override both the methods in the new interface and the methods in the old interface, as seen in listing 13.2.

Listing 13.2 Implementing a derived interface.

class Fireworks implements MonitoredRunnable {
private boolean running; // keeps track of state
void run() {
shootFireWorks();
}
boolean isRunning() { // provides access to other objects without
return(running); //allowing them to change the value of running
}
}

Because Fireworks implements MonitoredRunnable, it must override isRunning(), declared in MonitoredRunnable. Because MonitoredRunnable extends Runnable, it must also override run(), declared in Runnable.

While classes implement interfaces to inherit their properties, interfaces extend other interfaces. When extending more than one interface, separate each by a comma. This means that while classes cannot extend multiple classes, interfaces are allowed to extend multiple interfaces:
 

interface MonitoredRunnable extends java.lang.Runnable,java.lang.Cloneable {
boolean isRunning() {
}
}

The Interface Body

The body of an interface cannot specify the specific implementation of any methods, but it does specify their properties. In addition, interfaces may also contain final variables.

For example, declaring the MAKER variable in the Product interface allows you to declare a constant that will be employed by all classes implementing the Product interface.

Another good example of final fields in interfaces can be found in the java.awt.image.ImageConsumer interface. The interface defines a set of final integers that serve as standards for interpreting information. Because the RANDOMPIXELORDER variable equals 1, classes that implement the ImageConsumer interface can make reference to the variable and know that the value of 1 means that the pixels will be sent in a random order. This is shown in the setHints method of listing 13.3.

Listing 13.3 Pseudo code for a class implementing ImageConsumer.

public class MagnaImage implements ImageConsumer{
imageComplete(int status) {
...
}
setColorModel(ColorModel cm) {
...
}
setDimensions(int x, int y) {
...
}
setHints(int hints) {

if ((hints & RANDOMPIXELORDER)!=0){
...
}
}

setPixels(int x, int y, int w , int h, ColorModel cm , byte pixels[], int off, int scansize) {
...
}
setPixels(int x, int y, int w, int h, ColorModel cm, int pixels[], int off, int scansize) { ...
}
setProperties(Hashtable props) {
...
}
}

Methods

The main purpose of interfaces are to declare abstract methods that will be defined in other classes. As a result, if you are dealing with a class that implements an interface, you can be assured that these methods will be defined in the class. While this process is not overly complicated, there is one important difference that should be noticed.

The syntax for declaring a method in an interface is extremely similar to declaring a method in a class, but in contrast to methods declared in classes, methods declared in interfaces cannot possess bodies. An interface method consists of only a declaration. For example, the following two methods are complete if they are defined in an interface:

public int getPrice(int id);

public void showState();

However in a class, they would require method bodies:

public int getPrice(int id) {
if (id == 1)
return(5);
else
return(10);
}
public void showState() {
System.out.println("Massachusetts");
}

The method declaration does not determine how a method will behave; it does define how it will be used by defining what information it needs and what (if any) information will be returned. The method that is actually defined later in a class must have the same properties as you define in the interface. To make the best use of this fact, it is important to carefully consider factors like return type and parameter lists when defining the method in the interface.

Method declarations in interfaces have the following syntax:

public return_value nameofmethod (parameters) throws ExceptionList;

where everything in italics is optional. Also note that unlike normal method declarations in classes, declarations in interfaces are immediately followed by a semicolon.

All methods in interfaces are public by default, regardless of the presence or absence of the public modifier. This is in contrast to class methods which default to friendly.
 
It’s actually illegal to use any of the other standard method modifiers (including native, static, synchronized, final, private, protected, or private protected) when declaring a method in an interface.
 

Variables in Interfaces

Although interfaces are generally employed to provide abstract implementation of methods, you may also define variables within them. Because you cannot place any code within the bodies of the methods, all variables declared in an interface must be global to the class. Furthermore, regardless of the modifiers used when declaring the field, all fields declared in an interface are always public, final, and static.

While all fields will be created as public, final, and static, you do not need to explicitly state this in the field declaration. All fields default to public, static and final regardless of the presence of these modifiers.
 
It is, however, a good practice to explicitly define all fields in interfaces as public, final, and static to remind yourself (and other programmers) of this fact.
 

As seen in the Product interface, interface fields—like final static fields in classes—are used to define constants that can be accessed by all classes that implement the interface.

public interface Product {
//This variable is static and final
static final String MAKER = "My Corp";
//This variable is also static and final by default, even though not stated explicitly.
String PHONE = "555-123-4567";
public int getPrice(int id);
}

Implementing Interfaces

Now that you know how to create interfaces, let’s examine how they are used in developing classes. Listing 13.4 shows an example of a class that implements our Product interface.

Listing 13.4 Implementing an interface.

class Shoe implements Product {
public int getPrice(int id) {
if (id == 1)
return(5);
else
return(10);
}
public String getMaker() {
return(MAKER);
}
}

Of course, the code in the class can deal with functions other than those relating to the interface (such as the getMaker() method). But, in order to fulfill the requirements of implementing the Product interface, the class must override the getPrice(int) method.

Overriding Methods

Declaring a method in an interface is a good practice. However, the method cannot be used until a class implements the interface and overrides the given method.

Remember that if you implement an interface, you are required to override all methods declared in the interface. Failure to do so will make your class abstract.
 

Modifiers

As discussed earlier, methods declared in interfaces are by default assigned the public level of access. Consequently, because you cannot override a method to be more private than it already is, all methods declared in interfaces and overridden in classes must be assigned the public access modifier, unless they are explicitly made less public in the interface.

Of the remaining modifiers that may be applied to methods, only native and abstract may be applied to methods originally declared in interfaces.

Parameter List

Interface methods define a set a of parameters that must be passed to the method. Consequently, declaring a new method with the same name but a different set of parameters than the method declared in your interface overloads the method, not overrides it.

While there is nothing wrong with overloading methods declared in interfaces, it is also important to implement the method declared in the interface. Therefore, unless you declare your class to be abstract, you must override each method, employing the same parameter signature as in your interface (see listing 13.5). By the way, only one method satisfies the run() method required for Runnable.

Listing 13.5 Runner.java—A class that implements Runnable and has two run methods.

public void Runner implements Runnable {
//This method overloads the run() method it does not
//fulfill the requirements for Runnable
public void run(int max){
int count =0;
while (count++<max){
try{
Thread.sleep(500);
} catch (Exception e){}
}
}
//This method fulfills the requirement for Runnable.
//You must have this method.
public void run(){
while (true){
try{
Thread.sleep(500);
} catch (Exception e){}
}
}
}

See "Overloading," Chapter 11 for more information.
 

If the method String createName(int length, boolean capitalized) is declared in an interface, here are some valid and invalid examples of how to override it. The invalid methods can exist in addition to the valid ones, but will not be related to the interface:

Valid Invalid
String createName(int a, boolean b) String createName(boolean capitalized,int length)
String createName(int width,boolean formatted) String createName(int length)

Body

When creating a class that implements an interface, one of your chief concerns will be creating bodies for the methods originally declared in the interface. Unless you decide to make the method native, it is necessary to create the body for every method originally declared in your interface if you do not want to make your new class abstract.

The actual implementation and code of the body of your new method is entirely up to you. This is one of the good things about using interfaces. While the interface ensures that in a non-abstract class, its methods will be defined and will return an appropriate data type, the interface places no further restrictions or limitations on the method bodies.

Using Interfaces from Other Classes

You’ve learned how to create interfaces and build classes based on interfaces. However, interfaces are not useful unless you can develop classes that will either employ the derived classes or the interface itself.

Using an Interface's Fields

Although the fields of an interface must be both static and final, they can be extremely useful in your code.

The following example demonstrates that any variable from an interface can be referenced by using the same dot notation you use with classes. That means you can use java.awt.image.ImageConsumer.COMPLETESCANLINES just as with the class java.awt.Event you use with java.awt.Event.MOUSE_DOWN. This provides you with access to constants. Listing 13.6 shows an example of another ImageConsumer variable being used.

Listing 13.6 Using the constant fields of an interface.

class MyImageHandler {
/* The java.awt.image.ImageConsumer interface defines certain constants to serve as indicators.
STATICIMAGEDONE, which is set to equal 3, informs the consumer that the image is complete.*/

ImageConsumer picture;
void checkStatus(boolean done) {
if (done)
picture.imageComplete(ImageConsumer.STATICIMAGEDONE);

}
}

Using Interfaces as Types

One of the most important features of an interface is that it can be used as a data type. An interface variable can be used just as you would any class.

As a Parameter Type

In listing 13.7, you create a simple application that employs the Shoe class developed earlier. Because the Shoe class implements the Product interface, you may deal with the instances of the Shoe class either as standard Shoe objects or as objects based on the Product interface. Although both approaches produce the same results, treating the instance as an object based on the Product interface provides you with a more flexible and useful way of using the resources provided by the Product interface.

Listing 13.7 Using an interface as a parameter type.

class Store {
static Shoe hightop;
public static void init() {
hightop = new Shoe();
}
public static void main(String argv[]) {
init();
getInfo(hightop);
orderInfo(hightop);
}
public static void getInfo(Shoe item) {
System.out.println("This Product is made by "+ item.MAKER);
System.out.println("It costs $" + item.getPrice(1) + '\n');
}
public static void orderInfo(Product item) {
System.out.println("To order from " +item.MAKER + " call " + [ic:ccc]item.PHONE + ".");
System.out.println("Each item costs $" + item.getPrice(1));
}
}

Output

In the following example, the getInfo() methods treats hightop as a simple class with certain methods and fields. However, the interesting example is orderInfo(), which extracts almost the same information without knowing anything about a Shoe. Because a Shoe meets the requirements of a Product, you are able to implicitly cast a Shoe to become a Product. As a result, because you know that the Product interface declares certain features, you can be sure that these features, such as the getPrice() method, are present in the parameter item.

C:\dev>\jdk\java\bin\java Store
This Product is made by My Corp
It costs $5
To order from My Corp call 555-123-4567.
Each item costs $5

Notice that in treating hightop as a Product, you are implicitly casting it as a new data type without specifically stating so in your code. While the compiler has no trouble doing this, you could substitute that line of code in the Store class for the following:
 
orderInfo( (Product)hightop);
 
This statement would accomplish the same goal and is often more easier for other programmers to read, because it shows that orderInfo() accepts a Product, not a Shoe as its argument.
 

While in this simplistic example, it is not necessary to use the Product type as your argument, its use becomes apparent when you have multiple classes, each of which implements the same interface. For example, consider a more elaborate Store class with several items, all of which implemented the Product interface—such as in listing 13.8.

Listing 13.8 Using an interface as a type to deal with several classes.

interface Product {
String MAKER = "My Corp";
static final String PHONE = "555-123-4567";
public int getPrice(int id);
public void showName();
}
class Book implements Product {
public int getPrice(int id) {
if (id == 1)
return(20);
else
return(30);
}
public void showName() {

System.out.println("I'm a book!");
}
}
class Shoe implements Product {
public int getPrice(int id) {
if (id == 1)
return(5);
else
return(10);
}
public void showName() {

System.out.println("I'm a shoe!");
}
}
class store {
static Shoe hightop;
static Book using_java;
public static void init() {
hightop = new Shoe();
using_java = new Book();
}
public static void main(String argv[]) {
init();
orderInfo(hightop);
orderInfo(using_java);
}
public static void orderInfo(Product item) {
item.showName();
System.out.println("To order from " + item.MAKER + " call " + item.PHONE + ".");
System.out.println("Each item costs $" + item.getPrice(1));
}
}
Output:
C:\dev>\jdk\java\bin\java Store
I'm a shoe!
To order from My Corp call 555-123-4567.
Each item costs $5
I'm a book!
To order from My Corp call 555-123-4567.
Each item costs $20
o the constructor method.

Exceptions

In order for an interface method to throw an exception, the exception type (or one of its superclasses) must be listed in the exception list for the method as defined in the interface. However, when dealing with interface methods, exceptions are an exception. Here are the rules for overriding methods that throw exceptions:

In general, the exception list of the method which is declared in the interface, not the re-declared method determines which expectations can and cannot be thrown. In other words, when a re-declared method changes the exception list, it cannot add any exceptions that are not included in the original interface declaration.

As an example, examine the interface and method declarations in listing 13.9.

Listing 13.9 Alternate exception lists.

interface Example {
public int getPrice(int id) throws java.lang.RuntimeException;
}
class User implements Example {
public int getPrice(int id) throws java.awt.AWTException { // Illegal - Reason 1
// java.awt.AWTException is not a subclass ofjava.lang.RuntimeException
/// method body
}

public int getPrice(int id) {
if (id == 6)
throw new java.lang.IndexOutOfBoundsException(); // Legal - Reason 2
//IndexOutOfBoundsException is derived from RuntimeException
else
...
}
public int getPrice(int id) throws java.lang.IndexOutOfBoundsException { // Legal - Reason 1
// IndexOutOfBoundsException is derived from RuntimeException
if (id == 6)
throw new java.lang.ArrayIndexOutOfBoundsException(); // Legal - Reason 3
// ArrayIndexOutOfBoundsException is derived from IndexOutOfBoundsException
...
}


Previous PageTOCNext Page

| Previous Chapter | Next Chapter |

| Table of Contents | Book Home Page |

| Que Home Page | Digital Bookshelf | Disclaimer |


To order books from QUE, call us at 800-716-0044 or 317-361-5400.

For comments or technical support for our books and software, select Talk to Us.

© 1996, QUE Corporation, an imprint of Macmillan Publishing USA, a Simon and Schuster Company.