Default Static methods in Interface, introduced in Java 8 are as equally important to understand as like Lambdas.
Default Static methods in Interface address the problems with the current design of Interfaces and bridges the gap between Interfaces and Abstract Classes.
Default Static methods in Interface: Java 8
If you ask someone who is not familiar with Java 8 about the definition of an Interface, that first thing they say, Interface is a collection of methods with nobody attached to it.
Now with Java 8 in the market, the definition of Interface in developers mind has to be redefined. From Java 8, we can have method bodies in Interfaces as well, similar to Abstract Classes.
Why do we need Interfaces with bodies to methods?
- Suppose I am the designer of an interface and I want to provide one standard implementation to the methods of it, so that if anyone don’t implement that method to let the standard method get executed. This is not possible until Java 7, since Interfaces were not allowing concrete body methods. Till Java 7 interface was throwing error as shown below if we write body to it.
- You can’t add a new method to interface after a period, because all the client implementation has to provide a body for the new abstract method added.
- You can’t consider Abstract class to replace the drawbacks of Interfaces, because a class cannot extend multiple classes since Java doesn’t support Multiple Inheritance, but we can implement multiple interfaces to a single class
- You can’t even consider the creation of new Interface extending the existing interface, because of the client implementation. If you add a new method, then all the references of the old interface have to be replaced in their source
Default Static methods in Interface
Default Methods:
Default Methods allows interfaces to have a body to methods. So, this makes class implementing the interface not mandatory to provide body to the default method. This avoids the separate creation of abstract classes implementing the interface to provide method definition to common methods. If any class implementing interface wants to have their own implementation for the default method, they can still have it overriding the default method.
Example:
public interface IAddress {
public boolean addAddress(Address adr);
default String getCountryCapital(String country) {
if(country.equalsIgnoreCase("India")){
return "Delhi";
} else {
return null;
}
}
}
public class AddressImpl implements IAddress {
@Override
public boolean addAddress(Address adr) {
return AddressDAO.addAddress(adr);
}
@Override
public String getCountryCapital(String country) {
if(country.equalsIgnoreCase("Japan")) {
return "Tokyo";
} else
return null;
}
}
Explanation:
Here we have added a default method getCountryCapital(), which will check. If the country is India, it will return Delhi, else it will return null. The implementation class has overridden it and provided support for Japan.
Point to note:
Multiple Inheritance is not allowed in Java, since it causes the Diamond problem. Then, how do Interfaces now handle it? If a class implements two interfaces same default method (with the same signature), then the ambiguity caused to which method to be considered run time as default is called Diamond problem.
To solve this problem, Java 8 by default forces the class that implement two interfaces with same default method, to override it in its own implementation by throwing the error Duplicate default methods named getCountryCapital with the parameters (String) and (String) are inherited from the types IAddress2 and IAddress as shown below:
Static Methods:
Static Methods are similar to Default methods, but the only thing is, implementing classes cannot override the behaviour of the static method. This makes the system more standard instead of having each class its own implementation and introduction problems.
Still, the implementation classes can have a method with same name and signature, but cannot have @Override annotation on top of it, which will cause Compile time error saying The method getCountry() of type AddressImpl must override or implement a supertype method, asking to remove @Override annotation.
Example:
public interface IAddress {
public boolean addAddress(Address adr);
static String getCountry() {
return "India";
}
}
public class AddressImpl implements IAddress {
public boolean addAddress(Address adr) {
return AddressDAO.addAddress(adr);
}
public String getCountry() {
return "Japan";
}
}
Difference between Interface and Abstract Class after adding Default and Static methods in Interface:
If Interfaces in Java 8 are re-modified to bridge the gap with Abstract class then what is the difference between them?
- When should I use what?
- Abstract Classes:
- If you want methods with access modifiers other than public
- If you have more common methods
- If you want non-static, non-final fields
- If you want common code for the same group of classes
- Interfaces:
- If you want to have multiple inheritance
- If you want to have a common behaviour to all the implementations
- If your interface is used by a different group of unrelated classes.
- Abstract Classes:
Happy Learning 🙂