Interfaces


Overview

+How would you implement a single class that could maintain a sorted list of ints, Strings, or any other object?

Interfaces

A Java interface is a collection of constants and abstract methods. An abstract method is a method that does not have an implementation.

Essentially, the interface defines the behavior a class must support, and many classes may implement the same interface (that is, support the same function in different ways). You might consider an interface Drivable that defined an abstract method drive. A class Car might implement Drivable, as might a class Bicycle.

Defining an Interface

public interface Viewable {
	public void display();
}

An interface (as shown above) looks very similar to a class.

Implementing an Interface

To implement an interface, a class must specify that implements that interface and it must also provide implementations for all of the methods defined in the interface. If a class fails to implement one or more abstract methods from the interface, the compiler will complain.

public class Name implements Viewable {
	private String first;
	private String last;

	public Name(String first, String last) {
		this.first = first;
		this.last = last;
	}
	
	public void setFirst(String first) {
		this.first = first;
	}
	
	public void display() {
		System.out.println("First name: " + first);
		System.out.println("Last name: " + last);
	}


}

A class may also implement multiple interfaces.

public class C implements X, Y {
	//implementations for all methods in X and Y
}

Using Classes that Implement Interfaces

Because an interface does not provide implementation for its methods, it cannot be instantiated. The following piece of code would result a compiler error:

Viewable v = new Viewable();

However, the following code is perfectly valid:

Viewable v = new Name("Jane", "Wu");
v.display();

We describe Name as having an "is-a" relationship with Viewable, as in "a Name is a Viewable". Therefore, a variable that can refer to a Viewable can refer to a Name or an object of any other class that implements Viewable. Similarly, on a Viewable variable, you can invoke any method defined in Viewable.

Casting

Now, suppose you wanted to invoke the setFirst method on the variable v defined above. You might try v.setFirst("Bob"). However, because v is not of type Name, you cannot invoke methods from the Name class. This makes sense. v can refer to anything Viewable. For example, you might have a class Photo that implements Viewable. Therefore, Photo must implement display, but it probably won't implement setFirst. Following are a few valid and invalid samples, assuming a class Photo with a default constructor and no setFirst method:

Viewable v = new Name("Jane", "Wu");  //valid
v.display(); //valid
v.setFirst("Bob"); //invalid
v = new Photo();  //valid
v.display(); //valid
v.setFirst("Julie"); //invalid -- doesn't make sense!

In order to invoke the method setFirst on the variable v, we must use casting. Recall that casting tells the compiler to treat one type of variable as another type. (double)5 tells the compiler to treat the integer value 5 as a double. Similarly, (Name)v tells the compiler to treat the variable v as something of type Name. It would be used as follows:

Viewable v = new Name("Jane", "Wu");  
v.display(); 
Name n = (Name)v;
n.setFirst("Bob"); 
n.display(); //displays Bob Wu
v.display(); //also displays Bob Wu

Comparable

As a more concrete example, lets consider the Comparable interface. java.lang provides a Comparable interface with one method, compareTo, described as follows:

Compares this object with the specified object for order. Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.

In the foregoing description, the notation sgn(expression) designates the mathematical signum function, which is defined to return one of -1, 0, or 1 according to whether the value of expression is negative, zero or positive. The implementor must ensure sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) for all x and y. (This implies that x.compareTo(y) must throw an exception iff y.compareTo(x) throws an exception.)

The implementor must also ensure that the relation is transitive: (x.compareTo(y)>0 && y.compareTo(z)>0) implies x.compareTo(z)>0.

Finally, the implementer must ensure that x.compareTo(y)==0 implies that sgn(x.compareTo(z)) == sgn(y.compareTo(z)), for all z.

It is strongly recommended, but not strictly required that (x.compareTo(y)==0) == (x.equals(y)). Generally speaking, any class that implements the Comparable interface and violates this condition should clearly indicate this fact. The recommended language is "Note: this class has a natural ordering that is inconsistent with equals."

You'll notice that this is the method we use to compare Strings because the String class actually implements the Comparable interface.

+Revisiting our sorted list example, how would we use the Comparable interface to help us?


Sami Rollins

Date: 2007-09-19