Java8 Default Methods
## Java 8 Default Methods
Java 8 introduced a major update to the interface model by allowing interfaces to have **default methods**.
In simple terms, a default method is an interface method that contains its own implementation. Classes implementing the interface are not required to implement or override this method, though they can choose to do so.
To define a default method, you simply prefix the method signature with the `default` keyword.
---
### Why Were Default Methods Introduced?
Historically, Java interfaces were a double-edged sword. While they promoted clean design by separating abstraction from implementation, they had a major drawback: once an interface was published, modifying it was extremely difficult. Adding a new method to an existing interface meant breaking all classes that implemented it, as they would fail to compile until they implemented the new method.
For example, prior to Java 8, the Java Collections Framework interfaces (like `Collection` or `List`) did not have a `forEach` method. To support lambda expressions and internal iteration, the JDK designers needed to add `forEach` to these interfaces.
Without default methods, adding `forEach` to the `Iterable` interface would have broken millions of third-party Java applications. Default methods solved this backward-compatibility issue, allowing API designers to evolve interfaces seamlessly over time.
---
### Syntax
The syntax for declaring a default method in an interface is as follows:
```java
public interface Vehicle {
default void print() {
System.out.println("I am a vehicle!");
}
}
```
---
### Resolving Multiple Inheritance Conflicts
Because a Java class can implement multiple interfaces, a conflict arises if a class implements two interfaces that define the exact same default method signature.
Consider the following scenario:
```java
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-wheeled vehicle!");
}
}
```
If a class implements both `Vehicle` and `FourWheeler`, the compiler will throw a compilation error due to the ambiguity:
`class Car inherits unrelated defaults for print() from types Vehicle and FourWheeler`
To resolve this conflict, Java provides two primary solutions:
#### Solution 1: Override the Method with a Custom Implementation
You can override the conflicting method in the implementing class to provide a completely new behavior:
```java
public class Car implements Vehicle, FourWheeler {
@Override
public void print() {
System.out.println("I am a four-wheeled car!");
}
}
```
#### Solution 2: Explicitly Invoke a Specific Interface's Default Method
If you want to reuse the implementation of one of the parent interfaces, you can use the `super` keyword prefixed by the target interface name:
```java
public class Car implements Vehicle, FourWheeler {
@Override
public void print() {
// Explicitly call Vehicle's print implementation
Vehicle.super.print();
}
}
```
---
### Static Methods in Interfaces
In addition to default methods, Java 8 also introduced the ability to define **static methods** inside interfaces.
Like static methods in classes, interface static methods belong to the interface itself and cannot be overridden by implementing classes. They are invoked directly using the interface name.
```java
public interface Vehicle {
default void print() {
System.out.println("I am a vehicle!");
}
// Static method in an interface
static void blowHorn() {
System.out.println("Blowing horn!!!");
}
}
```
---
### Complete Code Example
The following complete example demonstrates how default methods, static methods, and conflict resolution work together.
Save the code below in a file named `Java8Tester.java`:
```java
public class Java8Tester {
public static void main(String args[]) {
Vehicle vehicle = new Car();
vehicle.print();
}
}
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-wheeled vehicle!");
}
}
class Car implements Vehicle, FourWheeler {
@Override
public void print() {
// Resolve conflict by calling both parent implementations
Vehicle.super.print();
FourWheeler.super.print();
// Call the static method of the Vehicle interface
Vehicle.blowHorn();
System.out.println("I am a car!");
}
}
```
#### Execution and Output
Compile and run the program using the terminal:
```bash
$ javac Java8Tester.java
$ java Java8Tester
I am a vehicle!
I am a four-wheeled vehicle!
Blowing horn!!!
I am a car!
```
---
### Key Considerations
When working with default methods, keep the following rules in mind:
1. **Class Wins Rule**: If a superclass defines a concrete method with the same signature as an interface's default method, the superclass method always takes precedence (the interface default method is ignored).
2. **Interface Wins Rule**: If a class inherits a default method from an interface, and a sub-interface also defines a default method with the same signature, the sub-interface's method takes precedence.
3. **Explicit Disambiguation**: If two independent interfaces provide default methods with the same signature, the implementing class must explicitly override the method to resolve the ambiguity.
YouTip