YouTip LogoYouTip

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.
← Java8 Optional ClassJava8 Method References β†’