Java Interface Default Methods

Summary: in this tutorial, you’ll learn about Java interface default methods, including their syntax, usage, and some best practices.

Introduction to Java interface default methods

In Java, an interface defines a contract that classes must adhere to. If you want to add new methods to an interface that is already implemented by multiple classes, you need to modify the classes and provide the implementations for the new methods. Otherwise, the code won’t compile.

To resolve this issue, Java 8 introduced the default methods so that interfaces can have methods with implementations.

Default methods allow you to add new methods to existing interfaces without breaking the classes that already implement them.

Defining Java interface default methods

To define a default method in an interface, you use the default keyword followed by the method signature and its implementation:

interface MyInterface {
    // Abstract method (no implementation required)
    void abstractMethod();

    // Default method with an implementation
    default void defaultMethod() {
        // Implementation code goes here
    }
}Code language: Java (java)

In this syntax:

  • Use the default keyword to define a default method.
  • The default method always has an implementation. Also, the default method is automatically available in all classes that implement the interface.
  • The class that implements the interface can override the default method by providing its own implementation.
  • An interface can have a combination of abstract and default methods.

Implementing an interface with default methods

The following shows how to define a class that implements the interface with the default method:

class MyClass implements MyInterface {
    @Override
    public void abstractMethod() {
        System.out.println("Implemented abstractMethod");
    }
}Code language: Java (java)

In this example, the MyClass can invoke the defaultMethod() method. Optionally, you can override the default method in the class like this:

class MyClass implements MyInterface {
    @Override
    public void abstractMethod() {
        System.out.println("Implemented abstractMethod");
    }

    // Optional: Overriding the default method
    @Override
    public void defaultMethod() {
        System.out.println("Custom implementation of defaultMethod");
    }
}Code language: Java (java)

Java interface default methods example

Let’s take an example of using default methods in an interface to understand how they work.

First, define an interface Shape:

interface Shape {
    double area();

    default void display(){
        System.out.println("Shape: " + getClass().getSimpleName());
        System.out.println("Area: " + area());
    }
}Code language: Java (java)

The Shape interface has two methods:

  • area() is an abstract method.
  • display() is a default method.

Any class that implements the Shape interface must provide an implementation for the area() method and optionally can override the display() default method.

Second, define a class Square that implements the Shape interface:

class Square implements Shape {
    private double length;
    public Square(double length){
        this.length = length;
    }

    @Override
    public double area() {
        return this.length * this.length;
    }
}Code language: Java (java)

The Square class implements the area() method and uses the default behavior of the display() method.

Third, define a class Rectangle that implements the Shape interface:

public class Rectangle implements Shape {
    private double length;
    private double width;

    public Rectangle(double length,double width){
        this.length = length;
        this.width = width;
    }
    @Override
    public double area() {
        return this.length * this.width;
    }

    @Override
    public void display(){
        System.out.println("***");
        System.out.println("Shape: " + getClass().getSimpleName());
        System.out.println("Area: " + area());
        System.out.println("***");
    }
}Code language: Java (java)

The Rectangle class implements the area() method that returns the area of the rectangle. Also, the Rectangle class overrides the display() method that provides its own specific implementation.

Fourth, use the Square and Rectangle classes in the main() method of the program:

public class App {
    public static void main(String[] args) {
        var square = new Square(10);
        square.display();

        var rectangle = new Rectangle(10, 5);
        rectangle.display();
    }
}Code language: Java (java)

Output:

Shape: Square
Area: 100.0
***
Shape: Rectangle
Area: 50.0
***Code language: Java (java)

When we call the display() method on the square object, it uses the default implementation provided by the Shape interface.

But when we call the display() method on the rectangle object, it uses the implementation implemented by the Rectangle class.

Resolving default method conflict

Java allows a class to implement multiple interfaces. If two interfaces have the same default method, a conflict will occur because the class doesn’t know which default method to use.

Let’s take a look at an example.

Suppose we have an interface called Output that has a default method display():

interface Output {
    default void display() {
        System.out.println(getClass().getSimpleName());
    }
}Code language: Java (java)

The Square class implements both Shape and Output interfaces:

public class Square implements Shape, Output {
    private double length;
    public Square(double length){
        this.length = length;
    }

    @Override
    public double area() {
        return this.length * this.length;
    }
}Code language: Java (java)

Now both display() methods of the Shape and Output interfaces are available in the Square class. It causes an ambiguous error.

To fix this, you need to explicitly override the display() method and select which method you want to use.

For example, if you want to use the display() method from the Shape interface, you can do it as follows:

package com.javazerotomastery.drawing;

public class Square implements Shape, Output {
    private double length;
    public Square(double length){
        this.length = length;
    }

    @Override
    public double area() {
        return this.length * this.length;
    }

    @Override
    public void display() {
        Shape.super.display();
    }
}Code language: Java (java)

The Shape.super.display() calls the display() method of the Shape interface.

If you want to use the display() method of the Output interface, you need to change the display() method to the following:

Output.super.display();Code language: Java (java)

Another option is that you can override the display() method completely like what the Rectangle class does.

Notice that because the Rectangle explicitly overrides the display() default method, it doesn’t have an ambiguous issue.

Summary

  • An interface can include both the abstract and the default methods.
  • A default method is a method with the default keyword and an implementation.
  • A default method is automatically available in all classes that implement the interface.
  • Use default methods to add new functionality to existing interfaces without breaking backward compatibility.
  • Classes may override the default method by providing a specific implementation.
  • If a class implements two or more interfaces that have the same default method, the class needs to explicitly override the default method.
  • Prefer using interfaces for defining contracts and abstract classes for sharing common implementation code among classes.