In this post, we will quickly discuss and cover default methods in Java. Java 8 brought a number of new and interesting new features, including lambda expressions, functional interfaces streams, Optional. This post covers the default methods in Java 8.
Introduction
Java 8 introduced a lot of new important features including default methods. In simple words, these are non-abstract methods implementations in interfaces, that are accessible to all classes who implements this interface, but the classes are not forced to override these methods. “default” keyword is used to denote a default method. So, starting from Java 8, if a new method added to an interface, and if it is not required by all classes implementing this interface, we can mark it as “default“.
The default method is also known as “defender method” or “virtual extension method”. In this post, we will show you in detail about default methods in Java and their use. Before going in detail, let me show you one simple example of “default method” :
interface Car {
default void printWheelCount() {
System.out.println("4");
}
void printColor();
}
public class MyCar implements Car {
public static void main(String args[]) {
MyCar myCar = new MyCar();
myCar.printColor();
myCar.printWheelCount();
}
@Override
public void printColor() {
System.out.println("Red");
}
}
Running code produce below output
Red
4
There are a few important points to keep in mind.
- printWheelCount is a default method in interface Car and printColor is an abstract method.
- MyCar” class is implementing the interface Car, but it is not overriding the default method printWheelCount.
- If MyCar class wants to add a different implementation for default method printWheelCount, it can override it similar to the abstract method printColor. The overridden method will be called if it overrides the default method.
1. Why the default method introduced in Java 8
We got the basic understanding of the default method in Java and how it works. Now, the next question that comes to our mind is “why the default method introduced in Java ?”. We already have abstract methods in interfaces. So, why this new concept? The one line answer to the above question is: “to support backward compatibility”. Let me explain you with a simple example.
Suppose we are developing one application for a ‘Headphone’ company with hundreds of different headphones. Each headphone has one different class and each of these classes implement one single interface that looks like below :
public interface Headphone {
public String getColor();
public String getFrequency();
public boolean isOverTheEar();
}
The implementation of the software is complete. After one year, the company introduced a new series of headphone with Bluetooth connectivity and they have asked us to extend the application for these new headphones. To do that, we need to add one new method to the parent interface class to check if the headphone is Bluetooth enabled or not :
public interface Headphone {
public String getColor();
public String getFrequency();
public boolean isOverTheEar();
public boolean isBluetoothEnabled();
}
But, if we add this new abstract method to the interface, we need to override it for all hundreds of classes for the old headphones !! This was the problem that we were facing till Java 7. Starting Java 8, we can easily solve this problem by marking the “isBluetoothEnabled” method as ‘default’ and override it only for the new classes.
public interface Headphone {
public String getColor();
public String getFrequency();
public boolean isOverTheEar();
default public boolean isBluetoothEnabled() {
return false;
}
}
Actually, the same thing was done for the Java 8 JDK. “forEach” method is introduced to the “Collection” interface and marked as “default” to avoid any changes for other classes that implement the Collection interface. Thus it helps us to support backward compatibility while adding new methods to an interface.
2. Conflicts on Multiple Inheritance and default methods
If one class is implementing more than one interface with same default method, it will show compile time error. e.g. :
interface MyCar {
default public String getColor() {
return "red";
}
}
interface MyBike {
default public String getColor() {
return "blue";
}
}
If one single class implements both MyCar and MyBike interfaces, it will throw one compile time error. So, we need to override this common method first and then we can return anything we want. Also, using ‘super’ keyword, the default method of the interface can be invoked.
public class MyVehicle implements MyCar, MyBike {
public static void main(String args[]) {
MyVehicle vehicle = new MyVehicle();
System.out.println(vehicle.getColor());
}
@Override
public String getColor() {
return MyCar.super.getColor();
}
}
3. Extending an interface that has a default method
We can create one new interface by extending another one. If the parent interface has one ‘default’ method, we have three different options while creating a new interface extending it :
- Don’t mention anything about the ‘default’ method in the new interface.
- Redeclare the ‘default’ method.
- Redefine the ‘default’ method.
3.1 Without mentioning anything about the ‘default’ method in the child interface
If we don’t mention anything about the ‘default’ method in the child interface, the child interface will inherit it from the parent interface. e.g. :
interface FirstInterface {
default public String getName() {
return "Inside first interface";
}
}
interface SecondInterface extends FirstInterface {}
public class MainClass implements SecondInterface {
public static void main(String args[]) {
MainClass mainClass = new MainClass();
System.out.println(mainClass.getName());
}
}
Output
Inside first interface
Here, MainClass is implementing the interface SecondInterface. This is a child interface that extends from the parent interface FirstInterface. FirstInterface has one default method ‘getName()
‘ inherited automatically to its child SecondInterface.
3.2 Redeclare the ‘default’ method
If we redeclare the ‘default’ method in the child interface, it will become abstract automatically. That means, we need to override it in the class that is implementing this interface. e.g. :
interface FirstInterface {
default public String getName() {
return "Inside first interface";
}
}
interface SecondInterface extends FirstInterface {
public String getName();
}
public class MainClass implements SecondInterface {
public static void main(String args[]) {
MainClass mainClass = new MainClass();
System.out.println(mainClass.getName());
}
@Override
public String getName() {
return "Inside MainClass";
}
}
Output
Inside MainClass
This example is same as the above but since we have redeclared ‘getName()
‘ inside SecondInterface, it becomes ‘abstract’. So, we need to override it in the ‘MainClass’.
3.3 Redefine the ‘default’ method
Redefining a ‘default’ method will override the original method. e.g. :
interface FirstInterface {
default public String getName() {
return "Inside first interface";
}
}
interface SecondInterface extends FirstInterface {
default public String getName() {
return "Inside second interface";
}
}
public class MainClass implements SecondInterface {
public static void main(String args[]) {
MainClass mainClass = new MainClass();
System.out.println(mainClass.getName());
}
}
Output
Inside second interface
It is same as like overriding a default method inside a class. If we redefine a default method in a child interface, it will ignore the same default method in the parent interface.
Summary
In this tutorial, we have learned about the default methods in Java 8 and different use cases, benefits of default method in Java. Starting from Java 8, these methods have enabled a totally new functionality to the Java interface. Using abstract methods with default method makes an interface more useful than it was before.
All the code samples shown in this article are available over on GitHub.
Comments are closed.