Interfaces

An interface defines a specification for classes to implement.  We declare interfaces by using the interface keyword followed by an identifier for the interface and a block of code that typically contains a list of method declarations among other things.

interface MyInterface {
    void foo();            // method declaration
}
interface MyOtherInterface {
    void bar();
}

When a class provides the methods specified in the interface, it can declare that it satisfies the interface specification by including an implements clause in the class definition.

class MyClass implements MyInterface {
    ...
    public void foo() {
        ...
    }
    ...
}

*** Notice that when implementing methods declared in an interface, the methods must have a public access modifier.

A class can implement more than one interface.  In this case, the implements clause lists the interfaces separated by commas.

class MyClass implements MyInterface, MyOtherInterface {
    ...
    public void foo() {
        ...
    }
    public void bar() {
        ...
    }
    ...
}

Contents

Interfaces are Forever

When we construct an interface for others to use, we are committing to the interface specification forever.  If we add a new method declaration to the interface at a later time, and other developers have written classes have implemented the older version of our interface then their implementation will fail under our new version.

To avoid this we have two options.

  1. Add a default implementations for all new methods in the new version of the interface.  The classes that extended the older version of the interface can either use the default implementations or override them.
  2. Create a completely new interface that extends the previous one.  That way classes that extended the older version of the interface won’t be affected.

Default Implementations

Interfaces may provide default implementations that classes which implement the interface may or may not override.  Default implementations are declared using the default keyword.

public interface Foo {
    default public void bar() {
        System.out.println("Hello");
    }
}

Extending an Interface

We can extend any interface using the extend keyword.

public interface Foo {
    public void bar();
}

public interface FooV2 extends Foo {
    public void box();
}

A class that implements FooV2 must provide implementations for box() as well as bar().

Static Variables, Static Methods, and Other Members

  • Interfaces can not contain instance variables but can have final static variables that are initialized.  If the variables are not declared final and static explicitly, they will be made so implicitly.
  • Interfaces may provide static methods, but static methods are not inherited by subclasses or subinterfaces and are only accessible using the interface name and the dot operator.  A class that implements an interface with a static method may include a method of the same signature as an interface static method.   The class implementation does not override the static method.  One is accessible via the class instance, the other is accessible using the interface name and dot operator.
  • Interfaces may also include enumerations, nested interfaces and classes.

Below is an example of an interface with a static member, a method declaration, a method with a default implementation and a static method.

interface MyInterface {
    final static int i = 100;

    void printi();                        // must be implemented

    default void printj(int j) {          // may be overridden
        System.out.println("j: " + j);
    }

    static void printk(int k) {           // may be overridden
        System.out.println("k: " + k);
    }
}

The class below implements the interface named MyInterface.

class MyClass implements MyInterface {
    public void printi() {
        System.out.println(“i: “ + i);
    }
}

The driver below show how to access the class and interface members.

public class Driver {
    public static void main(String[] args) {
        MyClass mc = new MyClass();
        mc.printi();
        mc.printj(10);
        //mc.printk(7);         //Will not compile unless defined in MyClass
        MyInterface.printk(7);
    }
}

If a class partially implements an interface, can still include an implements clause for the interface, but it must also be declared as abstract. We’ll cover abstract classes in the next lecture.

Only Use Interfaces to Define Types (Item 19)

An interface should define some functionality that classes are to implement.   Interfaces should not be used as a container for constant fields like the one below.

public class Foo { 
    public static final double CONST1 = 0.1; 
    public static final double CONST2 = 0.2;
}

If you need to declare a set of constants, include them in a class definition (not an interface).

public class Foo {
    private final Foo() {}  // prevents class from being instantiated
    public static final double CONST1 = 0.1;
    public static final double CONST2 = 0.2;
}

Refer to Objects by Their Interface Name (Item 52)

If a class implements an interface then a reference to an instance of that class can be stored in a variable having the interface’s type.  There are many uses cases for this.

One use is illustrated with the following example. Suppose we need to store a collection of Widgets in a data structure.  The List interface is implemented in a variety of classes including Vector.  Since this is the case we can hold a reference to a new Vector in a variable of type List as shown below.

List<Widget> widgets = new Vector<Widget>();

Referencing the data structure by the interface allows us to change that data structure at a later time without breaking the rest of the code that uses the widgets variable, so long as the new data structure implements List.

List<Widget> widgets = new ArrayList<Widget>();

© 2017 – 2019, Eric. All rights reserved.