Default methods in interfaces were introduced in Java 8 to allow interfaces to have method implementations. Prior to Java 8, interfaces could only declare abstract methods, meaning any class implementing an interface had to provide its own implementation for all the methods in that interface.
The introduction of default methods allowed developers to add new methods to interfaces without breaking existing implementations. This change was significant because it enabled backward compatibility, ensuring that existing codebases would not require modification when new methods were added to interfaces.
default
keyword and provides a body, much like a regular method in a class.The syntax for declaring a default method in an interface is straightforward:
interface InterfaceName {
// Abstract method (no body)
void abstractMethod();
// Default method (with body)
default void defaultMethod() {
System.out.println("Default method implementation");
}
}
In this example:
abstractMethod()
is a regular abstract method with no body, meaning any class that implements InterfaceName
must provide an implementation.defaultMethod()
is a default method with a body, meaning the implementing class can use this method without being required to override it.Let’s consider an example that demonstrates default methods:
interface Vehicle {
// Abstract method
void start();
// Default method with implementation
default void stop() {
System.out.println("Vehicle stopped");
}
}
class Car implements Vehicle {
@Override
public void start() {
System.out.println("Car started");
}
}
class Bike implements Vehicle {
@Override
public void start() {
System.out.println("Bike started");
}
// Bike overrides the default stop method
@Override
public void stop() {
System.out.println("Bike stopped in a custom way");
}
}
public class Main {
public static void main(String[] args) {
Vehicle car = new Car();
car.start(); // Output: Car started
car.stop(); // Output: Vehicle stopped (default method)
Vehicle bike = new Bike();
bike.start(); // Output: Bike started
bike.stop(); // Output: Bike stopped in a custom way (overridden method)
}
}
Vehicle
:Vehicle
interface declares an abstract method start()
that must be implemented by any class that implements the interface.stop()
that provides a default implementation for stopping a vehicle.Car
:Car
class implements the Vehicle
interface and provides its own implementation for the start()
method.stop()
method, the class uses the default implementation provided by the Vehicle
interface.Bike
:Bike
class also implements the Vehicle
interface and provides its own implementation for the start()
method.Car
, it overrides the stop()
method with its own custom implementation, demonstrating that a class can choose to override the default method if needed.Java allows a class to implement multiple interfaces, and it’s possible for those interfaces to contain default methods with the same signature. When this happens, the implementing class must resolve the conflict by overriding the method.
Example:
interface A {
default void print() {
System.out.println("A's implementation");
}
}
interface B {
default void print() {
System.out.println("B's implementation");
}
}
class C implements A, B {
@Override
public void print() {
// Resolving the conflict by overriding the method
A.super.print(); // Calling A's version
B.super.print(); // Calling B's version
}
}
public class Main {
public static void main(String[] args) {
C c = new C();
c.print();
}
}
In this example:
A
and B
interfaces have a default method print()
.C
implements both interfaces, so there is a conflict due to the two default methods.C
overrides the print()
method and explicitly calls the default methods from both A
and B
using A.super.print()
and B.super.print()
.A default method can coexist with abstract methods in an interface. Abstract methods still need to be implemented by any class that implements the interface, while default methods provide an option for the implementing class to use or override.
interface Machine {
// Abstract method
void start();
// Default method
default void stop() {
System.out.println("Machine stopped");
}
}
class Robot implements Machine {
@Override
public void start() {
System.out.println("Robot started");
}
// Using the default stop method
}
In this example, the Robot
class must implement the abstract start()
method but can choose to use the default stop()
method without overriding it.