Java Interfaces Tutorial

In this Java tutorial we learn about interfaces that, like abstract classes, doesn't provide implementations for their members.

We discuss how to define and implement one or more interfaces, how to create a default fallback interface method, and how to use static, private and private static interface methods.

Lastly, we discuss interface inheritance by extending interfaces.

Here's a table of contents of what you'll learn in this lesson:
(click on a link to skip to its section)

Let's jump right in.

What is an interface

An interface is very similar to an abstract classOpens up in a new page , the class members aren’t implemented.

If you remember from our tutorial on compositionOpens up in a new page , we spoke about favouring a has-a relationship over an is-a relationship. To recap quickly:

  • Inheritance can be abused, which may lead to a large, fragile hierarchy of classes.
  • Inheritance makes our classes tightly coupled and dependent on each other. We want them to be as loosely coupled as possible.

Interfaces allow us to have easy has-a relationships between classes. Instead of defining a class for each relationship, we define interfaces.

Even though an interface has nothing to do with inheritance, it does allow for polymorphic behavior in a similar way.

How to define an interface in Java

Interfaces are defined the same way as classes, except we use the interface keyword instead of the class keyword.

Interface methods aren’t implemented. We don’t add code blocks to methods, although they can contain parameters. Interfaces may also contain initialized constants (final variables).

Syntax:
interface I_interface_name {

    // constants
    public static final type constant_name = value;

    // methods
    public method(parameters);
}

A few things should be noted about interfaces and their members.

  • Even though interface methods are abstract, they are not marked as such.
  • Interface methods are implicitly public and interface properties are implicitly public static final .
    • We don’t have to specify the access modifier inside interfaces, but it’s good practice to do so.
  • A popular naming convention is to prefix the interface name with the capital letter I, to know at a glance that it’s an interface.
Example:
public class Program {
    public static void main(String[] args) {}
}

interface IFlyable {

    public static final int speed = 0;

    public void fly(int speed);
}

How to implement an interface in Java

Interfaces aren’t inherited, but rather implemented. We implement an interface with the implements keyword.

Syntax:
interface I_interface_name {

}

class class_name implements I_interface_name {

}
Example:
public class Program {
    public static void main(String[] args) {

        Sparrow s1 = new Sparrow();
        s1.fly();

        Plane p1 = new Plane();
        p1.fly();
    }
}

// interface
interface IFlyable {

    public void fly();
}

// implementations
class Sparrow implements IFlyable {

    // we must define the body
    // of the methods in the
    // interface we implement
    public void fly() {
        System.out.println("Sparrow, flying at a speed of 10");
    }
}

class Plane implements IFlyable {

    public void fly() {
        System.out.println("Plane, flying at a speed of 2000");
    }
}

Both ‘Sparrow’ and ‘Plane’ classes implement the ‘IFlyable’ interface and both must implement their own versions of the ‘fly()’ method.

If a class does not implement their own version of the methods in the interface, the compiler will raise an error.

Example:
public class Program {
    public static void main(String[] args) {}
}

// interface
interface IFlyable {

    public void fly();
}

// no implementation
class Sparrow implements IFlyable {}

In the example above, we don’t define a body for our ‘fly()’ method in our ‘Sparrow’ class, so the compiler raises an error.

Output:
 The type Sparrow must implement the inherited abstract method IFlyable.fly()

How to implement multiple interfaces in Java

Another benefit of interfaces is that we can implement more than one.

Please note that interfaces aren’t used for multiple inheritance, it’s just a benefit we get when using an interface.

To implement multiple interfaces, we separate them with a comma.

Syntax:
interface I_interface_name1 {

}

interface I_interface_name2 {

}

class class_name implements I_interface_name1, I_interface_name2 {

}
Example:
public class Program {
    public static void main(String[] args) {

        Sparrow s1 = new Sparrow();

        s1.fly();
        s1.hop();
    }
}

// interfaces
interface IFlyable {

    public void fly();
}
interface IHoppable {

    public void hop();
}

// implementation
class Sparrow implements IFlyable, IHoppable {

    public void fly() {
        System.out.println("Flying...");
    }
    public void hop() {
        System.out.println("Hopping...");
    }
}

In the example above, we create another interface called ‘IHoppable’. Because a sparrow can both fly and hop around, it can implement both interfaces.

If we decided to add a ‘Bunny’ class, all we need to do is implement the ‘IHoppable’ interface. Nothing breaks or needs to be changed because it’s all loosely coupled.

Default interface methods in Java

Java 8 and up supports methods in an interface with an implementation, called default methods. Before that, all interface methods were abstract.

To declare default methods inside interfaces, we use the default keyword.

Syntax:
interface I_interface_name {

    public default return_type() {
        // method body
    }
}
Example:
public class Program {
    public static void main(String[] args) {

        // the 'Sparrow' class doesn't
        // define a body for the 'fly'
        // method, but still uses it
        // because it's default has
        // been defined in the interface
        Sparrow s1 = new Sparrow();
        s1.fly();

        // the 'Plane' class defines
        // its own body for the fly
        // method
        Plane p1 = new Plane();
        p1.fly();
    }
}

// interfaces
interface IFlyable {

    public default void fly() {

        System.out.println("I can fly by default");
    }
}

// doesn't implement default method
class Sparrow implements IFlyable {}

// implements default method
class Plane implements IFlyable {

    public void fly() {
        System.out.println("I need science, machinery, fuel and a pilot to fly");
    }
}

At first glance it seems like we’re negating the purpose of interfaces and abstraction, but we’re not.

Think of it like a default method is the else conditional statement. If a class doesn’t provide an implementation for a method, it will use the default method in the interface.

In large, complex applications, we may have to track many implementations of an interface method. We could make a mistake and forget to define a body for the interface method in one of our classes.

In that case Java will simply use the default method, so our application doesn’t break.

Static, private and private static interface methods in Java

Java 8 and up supports static methods and Java 9 supports private and private static. A static method definition in the interface uses open and close curly braces instead of a semicolon.

A static method also doesn’t need to define a body in the class that implements it. But, if we don’t define a body for it, we won’t be able to use it and the compiler will raise a warning.

Example:
public class Program {
    public static void main(String[] args) {

        // if there is no implementation
        // for a static method, we won't
        // be able to use the method
        Sparrow.fly();
    }
}

// interface
interface IFlyable {

    // Java 8 static method
    // requires a body instead
    // of a semicolon
    public static void fly() {}
}

// a static method doesn't
// require an implementation
class Sparrow implements IFlyable {}

In the example above, we don’t implement a body for the static ‘fly()’ method. When we try to use it, the compiler raises a warning.

Output:
 The method fly() is undefined for the type Sparrow

How to extend (inherit from) an interface in Java

Similar to classes, interfaces can extend other interfaces. We use the extends keyword to inherit from an interface.

Syntax:
interface parent_name {

}

interface child_name extends parent_name {

}
Example:
public class Program {
    public static void main(String[] args) {

        Audi audi = new Audi();

        System.out.println("Audi model: " + audi.modelName);
        audi.logDrive();
    }
}

interface Car {

    public static void drive() {
        System.out.print("Driving...");
    }
}

interface Coupe extends Car {

    public default void logDrive() {
        Car.drive();
        System.out.print(" fast & furiously");
    }
}

class Audi implements Coupe {

    public String modelName = "RS5";
}

Summary: Points to remember

  • Interfaces allow for a loosely coupled Has-A relationship between classes, similar to composition.
  • Interfaces force other developers to provide their own implementation for our design.
  • Classes can implement multiple interfaces.
  • A default interface method may have its own body and acts as a fallback to avoid errors when an interface method doesn’t define its own body.
  • Java 8 introduced static interface methods and Java 9 introduced private and private static interface methods.