Previous | Table of Contents | Next |
14.3.9.3. Using Interfaces
Suppose we implement DrawableCircle and DrawableSquare just as we implemented DrawableRectangle in Example 14.23. As we saw earlier, instances of these classes can be treated as instances of the abstract Shape class. They can also be treated as instances of the Drawable interface. Example 14.24 demon-strates this.
EXAMPLE 14.24. Casting objects to their interface type.
Shape[] shapes = new Shape[3]; // Create an array to hold shapes Drawable[] drawables = new Drawable[3]; // and an array to hold drawables. // Create some drawable shapes. DrawableCircle dc = new DrawableCircle(1.1); DrawableSquare ds = new DrawableSquare(2.5); DrawableRectangle dr = new DrawableRectangle(2.3, 4.5); // The shapes can be assigned to both arrays. shapes[0] = dc; drawables[0] = dc; shapes[1] = ds; drawables[1] = ds; shapes[2] = dr; drawables[2] = dr; // Compute total area and draw the shapes by invoking // the Shape and the Drawable abstract methods. double total_area = 0; for(int i = 0; i < shapes.length; i++) { total_area += shapes[i].area(); // Compute the area of the shapes drawables[i].setPosition(i*10.0, i*10.0); drawables[i].draw(draw_window); // Assume draw_window defined somewhere }
What this example demonstrates is that interfaces are data types in Java, just as classes are, and that when a class implements an interface, instances of that class can be assigned to variables of the interface type. Dont interpret this example to imply that you must assign a DrawableRectangle object to a Drawable variable before you can invoke the draw() method or that you must assign it to a Shape variable before you can invoke the area() method. DrawableRectangle defines draw() and inherits area() from its Rectangle superclass, and so you can always invoke these methods.
14.3.9.4. Implementing Multiple Interfaces
Suppose we wanted shapes that could be scaled to be larger or smaller. One way we could do this is by defining a Scalable interface and implementing subclasses of DrawableRectangle and the other classes. To do this, though, the new subclass would have to implement both the Drawable interface and the Scalable interface. This is no problem. You may specify a list of comma-separated interfaces in the implements clause of any class:
public class DrawableScalableRectangle extends DrawableRectangle implements Drawable, Scalable { // The methods of the Scalable interface must be implemented here. }
When a class implements more than one interface, it means simply that it must provide an implementation for all of the abstract methods in all of its interfaces.
14.3.9.5. Constants in Interfaces
As we noted above, constants may appear in interface definitions. What does it mean to implement an interface that contains constants? It simply means that the class that implements the interface inherits the constants (in a sense) and can use them as if they were defined directly in the class. There is no need to prefix them with the name of the interface, and there is no need to provide an implementation of the constants:
class A { static final int CONSTANT1 = 3; } interface B { static final int CONSTANT2 = 4; } class C implements B { void f() { int i = A.CONSTANT1; // Have to use the class name here. int j = CONSTANT2; // No class name here, because we implement } // the interface that defines this constant. }
When you have a set of constants used by more than one class within a package (for example, a port number and other protocol constants used by a client and server), it is convenient to define them in an interface that contains no abstract methods. Then, any class that wants to use those constants needs only to declare that it implements the interface.
14.3.9.6. Extending Interfaces
Interfaces can have sub-interfaces, just like classes can have subclasses. A sub-interface inherits all the abstract methods and constants of its super-interface, and may define new abstract methods and constants. Interfaces are different from classes in one very important way, however.
An interface can extend more than one interface at a time:
public interface Transformable extends Scalable, Rotateable, Reflectable { } public interface DrawingObject extends Drawable, Transformable { } public class Shape implements DrawingObject { ... }
An interface that extends more than one interface inherits all the abstract methods and constants from each of those interfaces, and may define its own additional abstract methods and constants. A class that implements such an interface must implement the abstract methods defined in the interface itself as well as all the abstract methods inherited from all of the super-interfaces.
14.3.9.7. Marker Interfaces
Another technique that is sometimes useful is to define an interface that is entirely empty. A class can implement this interface to provide additional information about itself. The Cloneable interface in java.lang is an example of this type of marker interface. It defines no methods, but serves simply to identify the class as one that will allow its internal state to be cloned by the clone() method of the Object class. In Java 1.1, java.io.Serializable is another such marker interface. You can test whether a class implements a marker interface (or any interface) using the instanceof operator.
Previous | Table of Contents | Next |