Interfaces in Java

Interfaces in Java represent pure behavioral contracts without specifying any sort of implementation or inheritance hierarchy.

Technically, all an interface does is to specify that certain methods with particular signatures (name, number of parameters, and parameter types) exists for the class that implement it.

For instance, suppose we define the interface IMyInterface:

interface IMyInterface {

int method1(double x);

void method2();

Object method3(JFrame f);

}

The above definition means that any class that implements IMyInterface must have at least three public methods:

  1. A method called method1 that returns an int and takes a double as an input parameter.
  2. A method called method2 that has no (void) return value and takes no input parameters.
  3. A method called method3 that returns an Object and takes a JFrame as an input parameter.

For instance suppose the class MyClass inherits from MySuperC lass and implements the IMyInterface interface.

class MyClass extends MySuperClass implements IMyInterface {

public int method1(double x) { /* method body code */ }

public void method2() { /* method body code */ }

public char anotherMethod() { /* method body code */ }

// More method declarations.

}

class MySuperClass {

public Object method3(JFrame f) { /* method body code */ }

//More method declarations

}

Note that MyClass declares all three methods in IMyInterface -- one of which is inherited from its superclass. Thus MyClass provides the implementation for the behaviors specified by IMyInterface.

Classes with different superclasses can implement the same interface because the interface does not specify the implementation of the methods, only that they exist.

It is extremely important to recognize that the Java code for interfaces does not specify the semantics of the methods that are defined. That is, the Java syntax only specifies the method signatures and return values, but not what the methods are supposed to do. These behavior are a crucial part of the interface contract however.

For instance if an interface specifies the existence of a method called, double transform(double x), it must also specify (as a comment) the tranformation that a client object is expecting to be performed on x. Any class that implements that interface must implement double transform(double x) in a manner that the input parameter is transformed in that specified manner. If the class does not implement the method as per the interface specification, any object expecting to interact with it via that interface will get unexpected results.

Classes can implement more than one interface, which is how Java implements multiple inheritance ("interface multiple inheritance"). This technique by-passes many of the multiple behavior problems associated with "class multiple inheritance" as found in C++ because the interfaces do not specify any sort of implementation. However, this can cause problems if two interfaces specify methods with the same signature but with different semantics. The compiler will not complain about this because the Java language does not include the specification of the semantics of the methods, however because there will be only a single implementation of a method for the multiple specifications in the different interfaces, the multiple semantics of the interfaces will not be supported correctly by the class.

The syntax to implement multiple interfaces is:

class MyClass implements Interface1, Interface2, Interface3 { ... }

Variables can be declared as the type of an interface and assigned to reference any object that implements that interface:

IMyInterface z = new MyClass();

The methods that can be called on the variable z are now restricted to only those methods specified by IMyInterface:

int x = z.method1(3.14);

z.method2();

Object o = z.method3(aFrame);

The code that uses z is thus "decoupled" from the implementation of the methods that it invokes on z as it only cares that z has those 3 methods and does not care what sort of object z actually is. This decoupling is crucial for managing large object systems as it enables the system complexity to grow as the number of objects rather than as the number of objects squared..