Java Default Methods in Interfaces: Enhancing Flexibility and Backward Compatibility

Discover the significance of default methods in Java interfaces introduced in Java 8. Learn how default implementations allow for backward compatibility while enabling new functionalities like lambda expressions. Understand how default methods enhance existing interfaces, such as List and Collection, without breaking current implementations.



Java - Default Methods in Interfaces

Java Default Methods Overview

Java introduced default method implementation in interfaces with Java 8. Before Java 8, interfaces could only contain abstract methods. This feature was added for backward compatibility, allowing older interfaces to utilize lambda expressions.

For instance, the List or Collection interfaces lacked a forEach method declaration, and adding such a method would break existing implementations. Default methods enable the List and Collection interfaces to include a default implementation of the forEach method without requiring implementing classes to define it.

Syntax

The following is the syntax for defining a default method in an interface in Java:

Syntax

public interface Vehicle {
default void print() {
System.out.println("I am a vehicle!");
}
}

Learn Java in-depth with real-world projects through our Java certification course. Enroll to become a certified expert and boost your career.

Java Default Method Example

Below is an example demonstrating the use of default methods in interfaces:

Tester Class Implementation

package com.tutorialsarena;

interface Vehicle {
// default method must have an implementation
default void print() {
System.out.println("I am a vehicle!");
}
}

// The implementing class does not need to implement the default method
public class Tester implements Vehicle {
public static void main(String args[]) {
Tester tester = new Tester();
// The implementing class can access the default method as its own
tester.print(); 
}
}

Output

Output

I am a vehicle!

Default Methods in Multiple Inheritance

When using default methods in interfaces, a class may implement two interfaces that contain the same default method, leading to ambiguity. The following example illustrates how to resolve this issue:

Ambiguity Resolution Example

public interface Vehicle {
default void print() {
System.out.println("I am a vehicle!");
}
}

public interface FourWheeler {
default void print() {
System.out.println("I am a four wheeler!");
}
}

// Solution: Create an own method that overrides the default implementation
public class Car implements Vehicle, FourWheeler {
public void print() {
System.out.println("I am a four wheeler car vehicle!");
}
}

After overriding the default method with your own implementation, you can use the print method from the Car class as follows:

Tester Class with Car Implementation

package com.tutorialsarena;

interface Vehicle {
default void print() {
System.out.println("I am a vehicle!");
}
}

interface FourWheeler {
default void print() {
System.out.println("I am a four wheeler!");
}
}

class Car implements Vehicle, FourWheeler {
// Overriding the default method resolves the ambiguity
public void print() {
System.out.println("I am a four wheeler car vehicle!");
}
}

public class Tester {
public static void main(String args[]) {
Car car = new Car();
car.print(); 
}
}

Output

Output

I am a four wheeler car vehicle!

Calling Default Methods of Interfaces

Another way to resolve the ambiguity is to call the default method of a specified interface using super:

Calling Default Method Example

public class Car implements Vehicle, FourWheeler {
public void print() {
// Call the default method from the Vehicle interface
Vehicle.super.print();
}
}

Example: Calling Default Method

In this example, the Car class implements two interfaces, and it can call the default method from either interface:

Tester Class with Super Call

package com.tutorialsarena;

interface Vehicle {
default void print() {
System.out.println("I am a vehicle!");
}
}

interface FourWheeler {
default void print() {
System.out.println("I am a four wheeler!");
}
}

class Car implements Vehicle, FourWheeler {
// Use the default method of an interface
public void print() {
FourWheeler.super.print();
}
}

public class Tester {
public static void main(String args[]) {
Car car = new Car();
car.print(); 
}
}

Output

Output

I am a four wheeler!

Static Default Methods in Java

Java 8 also allows interfaces to have static default methods, which act as helper or utility functions. These methods help encapsulate code better:

Static Default Method Example

public interface Vehicle {
default void print() {
System.out.println("I am a vehicle!");
}

static void blowHorn() {
System.out.println("Blowing horn!!!");
}
}

Example: Calling Static Default Method of Interface

Below is an example where we call the static method directly:

Tester Class with Static Method Call

package com.tutorialsarena;

interface Vehicle {
default void print() {
System.out.println("I am a vehicle!");
}

static void blowHorn() {
System.out.println("Blowing horn!!!");
}
}

interface FourWheeler {
default void print() {
System.out.println("I am a four wheeler!");
}
}

class Car implements Vehicle, FourWheeler {
public void print() {
// Call the Vehicle interface default print method   
Vehicle.super.print();
FourWheeler.super.print();
// Call the static method from the Vehicle interface  
Vehicle.blowHorn();
System.out.println("I am a car!");
}
}

public class Tester {
public static void main(String args[]) {
Vehicle vehicle = new Car();
vehicle.print();
// Call the Vehicle interface static blowHorn method 
Vehicle.blowHorn();
}
}

Output

Output

I am a vehicle!
I am a four wheeler!
Blowing horn!!!
I am a car!
Blowing horn!!!