Default Methods in Interfaces: The Complete Guide

Introduction

Imagine you're managing a library system, and you need to add new features to all books without breaking existing code. Default methods in Java interfaces are like adding new chapters to a book contract - all books automatically get the new content, but can choose to rewrite it if they want!

Default methods were introduced in Java 8 to allow interfaces to have method implementations without breaking existing implementations. This revolutionized interface design and enabled powerful new patterns.


What are Default Methods?

Default methods are interface methods that have an implementation. They're declared with the default keyword and provide a default implementation that implementing classes can use or override.

Key Characteristics:

  • βœ… Method with implementation in interface
  • βœ… Uses default keyword
  • βœ… Backward compatible - doesn't break existing implementations
  • βœ… Can be overridden by implementing classes
  • βœ… Enables interface evolution

Why Default Methods Were Introduced?

Before Java 8:

interface List {
void add(Object item);     // All implementing classes MUST implement this
// Cannot add new methods without breaking all implementations
}

After Java 8:

interface List {
void add(Object item);
default void sort() {      // New method with default implementation
// sorting logic here
}
}

Code Explanation with Examples

Example 1: Basic Default Methods

// 🎯 INTERFACE WITH DEFAULT METHODS
interface Vehicle {
// 🎯 REGULAR ABSTRACT METHOD (must be implemented)
void start();
void stop();
// 🎯 DEFAULT METHOD (has implementation)
default void honk() {
System.out.println("πŸš— Vehicle is honking: Beep Beep!");
}
// 🎯 ANOTHER DEFAULT METHOD
default void displayInfo() {
System.out.println("This is a vehicle interface");
}
// 🎯 STATIC METHOD IN INTERFACE (Java 8+)
static void vehicleFactoryInfo() {
System.out.println("🏭 Vehicle Factory - All vehicles must implement start() and stop()");
}
}
// 🎯 CLASS IMPLEMENTING INTERFACE (CAN USE DEFAULT METHODS AS-IS)
class Car implements Vehicle {
private String model;
public Car(String model) {
this.model = model;
}
// 🎯 MUST IMPLEMENT ABSTRACT METHODS
@Override
public void start() {
System.out.println("πŸš™ " + model + " car is starting... Vroom!");
}
@Override
public void stop() {
System.out.println("πŸš™ " + model + " car is stopping...");
}
// 🎯 CAN USE DEFAULT METHODS WITHOUT IMPLEMENTING THEM
// honk() and displayInfo() are inherited automatically
}
// 🎯 CLASS THAT OVERRIDES DEFAULT METHOD
class Truck implements Vehicle {
private String model;
public Truck(String model) {
this.model = model;
}
@Override
public void start() {
System.out.println("πŸš› " + model + " truck is starting... BRRRRUM!");
}
@Override
public void stop() {
System.out.println("πŸš› " + model + " truck is stopping...");
}
// 🎯 OVERRIDING DEFAULT METHOD
@Override
public void honk() {
System.out.println("πŸš› " + model + " truck is honking: HOOONK! HOOONK!");
}
// 🎯 ADDING NEW METHOD
public void loadCargo() {
System.out.println("πŸš› " + model + " is loading cargo...");
}
}
// 🎯 CLASS THAT USES DEFAULT METHOD AND ADDS ITS OWN BEHAVIOR
class Motorcycle implements Vehicle {
private String model;
public Motorcycle(String model) {
this.model = model;
}
@Override
public void start() {
System.out.println("🏍️ " + model + " motorcycle is starting... Vroom vroom!");
}
@Override
public void stop() {
System.out.println("🏍️ " + model + " motorcycle is stopping...");
}
// 🎯 USING DEFAULT METHOD BUT EXTENDING IT
@Override
public void displayInfo() {
Vehicle.super.displayInfo(); // Call default implementation
System.out.println("🏍️ Specifically, this is a " + model + " motorcycle");
}
}
public class BasicDefaultMethods {
public static void main(String[] args) {
System.out.println("=== BASIC DEFAULT METHODS DEMONSTRATION ===");
// 🎯 CREATING VEHICLES
Car car = new Car("Toyota Camry");
Truck truck = new Truck("Ford F-150");
Motorcycle motorcycle = new Motorcycle("Harley Davidson");
// 🎯 USING ABSTRACT METHODS (MUST BE IMPLEMENTED)
System.out.println("\n1. ABSTRACT METHODS (MUST IMPLEMENT):");
car.start();
truck.start();
motorcycle.start();
// 🎯 USING DEFAULT METHODS (INHERITED AUTOMATICALLY)
System.out.println("\n2. DEFAULT METHODS (AUTOMATICALLY AVAILABLE):");
System.out.println("--- Car (uses default honk) ---");
car.honk();
car.displayInfo();
System.out.println("--- Truck (overrides default honk) ---");
truck.honk();
truck.displayInfo();
System.out.println("--- Motorcycle (uses default honk, extends displayInfo) ---");
motorcycle.honk();
motorcycle.displayInfo();
// 🎯 STATIC METHOD IN INTERFACE
System.out.println("\n3. STATIC METHOD IN INTERFACE:");
Vehicle.vehicleFactoryInfo();
// 🎯 POLYMORPHISM WITH DEFAULT METHODS
System.out.println("\n4. POLYMORPHISM WITH DEFAULT METHODS:");
Vehicle[] vehicles = {car, truck, motorcycle};
for (Vehicle vehicle : vehicles) {
System.out.println("\n--- Processing Vehicle ---");
vehicle.start();
vehicle.honk(); // Calls appropriate version (default or overridden)
vehicle.displayInfo();
vehicle.stop();
}
// 🎯 BENEFITS OF DEFAULT METHODS
System.out.println("\n5. BENEFITS OF DEFAULT METHODS:");
System.out.println("βœ… Backward Compatibility: Add methods without breaking existing code");
System.out.println("βœ… Code Reuse: Common implementation in one place");
System.out.println("βœ… Flexibility: Classes can use default or provide their own");
System.out.println("βœ… Interface Evolution: Interfaces can grow over time");
// 🎯 TRUCK-SPECIFIC METHOD
System.out.println("\n6. CLASS-SPECIFIC METHODS:");
truck.loadCargo();
}
}

Output:

=== BASIC DEFAULT METHODS DEMONSTRATION ===
1. ABSTRACT METHODS (MUST IMPLEMENT):
πŸš™ Toyota Camry car is starting... Vroom!
πŸš› Ford F-150 truck is starting... BRRRRUM!
🏍️ Harley Davidson motorcycle is starting... Vroom vroom!
2. DEFAULT METHODS (AUTOMATICALLY AVAILABLE):
--- Car (uses default honk) ---
πŸš— Vehicle is honking: Beep Beep!
This is a vehicle interface
--- Truck (overrides default honk) ---
πŸš› Ford F-150 truck is honking: HOOONK! HOOONK!
This is a vehicle interface
--- Motorcycle (uses default honk, extends displayInfo) ---
πŸš— Vehicle is honking: Beep Beep!
This is a vehicle interface
🏍️ Specifically, this is a Harley Davidson motorcycle
3. STATIC METHOD IN INTERFACE:
🏭 Vehicle Factory - All vehicles must implement start() and stop()
4. POLYMORPHISM WITH DEFAULT METHODS:
--- Processing Vehicle ---
πŸš™ Toyota Camry car is starting... Vroom!
πŸš— Vehicle is honking: Beep Beep!
This is a vehicle interface
πŸš™ Toyota Camry car is stopping...
--- Processing Vehicle ---
πŸš› Ford F-150 truck is starting... BRRRRUM!
πŸš› Ford F-150 truck is honking: HOOONK! HOOONK!
This is a vehicle interface
πŸš› Ford F-150 truck is stopping...
--- Processing Vehicle ---
🏍️ Harley Davidson motorcycle is starting... Vroom vroom!
πŸš— Vehicle is honking: Beep Beep!
This is a vehicle interface
🏍️ Specifically, this is a Harley Davidson motorcycle
🏍️ Harley Davidson motorcycle is stopping...
5. BENEFITS OF DEFAULT METHODS:
βœ… Backward Compatibility: Add methods without breaking existing code
βœ… Code Reuse: Common implementation in one place
βœ… Flexibility: Classes can use default or provide their own
βœ… Interface Evolution: Interfaces can grow over time
6. CLASS-SPECIFIC METHODS:
πŸš› Ford F-150 is loading cargo...

Example 2: Real-World Library System

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
// 🎯 LIBRARY ITEM INTERFACE WITH DEFAULT METHODS
interface LibraryItem {
// 🎯 ABSTRACT METHODS
String getTitle();
String getAuthor();
String getItemId();
boolean isAvailable();
// 🎯 DEFAULT METHODS - COMMON FUNCTIONALITY
default void checkOut(String borrower) {
System.out.println("πŸ“– " + getTitle() + " checked out to: " + borrower);
System.out.println("   Due date: " + calculateDueDate());
}
default void checkIn() {
System.out.println("πŸ“– " + getTitle() + " has been returned");
}
default LocalDate calculateDueDate() {
return LocalDate.now().plusWeeks(2); // 2 weeks loan period
}
default void displayBasicInfo() {
System.out.println("πŸ“š " + getTitle() + " by " + getAuthor());
System.out.println("   ID: " + getItemId() + " | Available: " + isAvailable());
}
// 🎯 STATIC UTILITY METHOD
static void displayLibraryRules() {
System.out.println("=== LIBRARY RULES ===");
System.out.println("1. Loan period: 2 weeks");
System.out.println("2. Maximum 10 items per borrower");
System.out.println("3. Late fee: $0.25 per day");
}
}
// 🎯 BOOK CLASS IMPLEMENTING INTERFACE
class Book implements LibraryItem {
private String title;
private String author;
private String isbn;
private boolean available;
private int pageCount;
public Book(String title, String author, String isbn, int pageCount) {
this.title = title;
this.author = author;
this.isbn = isbn;
this.pageCount = pageCount;
this.available = true;
}
// 🎯 IMPLEMENT ABSTRACT METHODS
@Override
public String getTitle() { return title; }
@Override
public String getAuthor() { return author; }
@Override
public String getItemId() { return isbn; }
@Override
public boolean isAvailable() { return available; }
// 🎯 USING DEFAULT METHODS AS-IS
// checkOut(), checkIn(), calculateDueDate(), displayBasicInfo() inherited
// 🎯 BOOK-SPECIFIC METHOD
public void readSample() {
System.out.println("πŸ“– Reading sample of: " + title);
System.out.println("   Pages: " + pageCount);
}
}
// 🎯 DVD CLASS IMPLEMENTING INTERFACE
class DVD implements LibraryItem {
private String title;
private String director;
private String dvdId;
private boolean available;
private int durationMinutes;
public DVD(String title, String director, String dvdId, int durationMinutes) {
this.title = title;
this.director = director;
this.dvdId = dvdId;
this.durationMinutes = durationMinutes;
this.available = true;
}
// 🎯 IMPLEMENT ABSTRACT METHODS
@Override
public String getTitle() { return title; }
@Override
public String getAuthor() { return director; } // Director as "author"
@Override
public String getItemId() { return dvdId; }
@Override
public boolean isAvailable() { return available; }
// 🎯 OVERRIDE DEFAULT METHOD FOR DVD-SPECIFIC BEHAVIOR
@Override
public void checkOut(String borrower) {
System.out.println("πŸ“€ " + title + " DVD checked out to: " + borrower);
System.out.println("   Due date: " + calculateDueDate());
System.out.println("   Duration: " + durationMinutes + " minutes");
}
@Override
public LocalDate calculateDueDate() {
return LocalDate.now().plusWeeks(1); // DVDs have 1-week loan
}
// 🎯 DVD-SPECIFIC METHOD
public void playTrailer() {
System.out.println("🎬 Playing trailer for: " + title);
}
}
// 🎯 AUDIOBOOK CLASS IMPLEMENTING INTERFACE
class Audiobook implements LibraryItem {
private String title;
private String author;
private String audioId;
private boolean available;
private int audioLength; // in minutes
private String narrator;
public Audiobook(String title, String author, String audioId, int audioLength, String narrator) {
this.title = title;
this.author = author;
this.audioId = audioId;
this.audioLength = audioLength;
this.narrator = narrator;
this.available = true;
}
// 🎯 IMPLEMENT ABSTRACT METHODS
@Override
public String getTitle() { return title; }
@Override
public String getAuthor() { return author; }
@Override
public String getItemId() { return audioId; }
@Override
public boolean isAvailable() { return available; }
// 🎯 OVERRIDE DEFAULT METHOD
@Override
public void displayBasicInfo() {
System.out.println("🎧 " + title + " by " + author);
System.out.println("   Narrated by: " + narrator);
System.out.println("   Duration: " + audioLength + " minutes");
System.out.println("   ID: " + audioId + " | Available: " + available);
}
// 🎯 AUDIOBOOK-SPECIFIC METHOD
public void playSample() {
System.out.println("🎧 Playing sample of: " + title);
System.out.println("   Narrated by: " + narrator);
}
}
// 🎯 LIBRARY MANAGEMENT SYSTEM
class Library {
private List<LibraryItem> items;
private String libraryName;
public Library(String libraryName) {
this.libraryName = libraryName;
this.items = new ArrayList<>();
System.out.println("πŸ›οΈ Library created: " + libraryName);
}
public void addItem(LibraryItem item) {
items.add(item);
System.out.println("βž• Added to library: " + item.getTitle());
}
public void displayAllItems() {
System.out.println("\n=== " + libraryName.toUpperCase() + " CATALOG ===");
for (LibraryItem item : items) {
item.displayBasicInfo(); // Using default method
System.out.println("---");
}
}
public void checkoutItem(String itemId, String borrower) {
for (LibraryItem item : items) {
if (item.getItemId().equals(itemId) && item.isAvailable()) {
item.checkOut(borrower); // Using default method (may be overridden)
return;
}
}
System.out.println("❌ Item not available or not found: " + itemId);
}
// 🎯 SEARCH FUNCTIONALITY USING DEFAULT METHODS
public void searchByAuthor(String author) {
System.out.println("\nπŸ” Search results for author: " + author);
boolean found = false;
for (LibraryItem item : items) {
if (item.getAuthor().toLowerCase().contains(author.toLowerCase())) {
item.displayBasicInfo();
found = true;
}
}
if (!found) {
System.out.println("No items found for author: " + author);
}
}
}
public class LibrarySystemDemo {
public static void main(String[] args) {
System.out.println("=== REAL-WORLD LIBRARY SYSTEM WITH DEFAULT METHODS ===");
// 🎯 DISPLAY LIBRARY RULES (STATIC METHOD)
LibraryItem.displayLibraryRules();
// 🎯 CREATE LIBRARY
Library cityLibrary = new Library("City Public Library");
// 🎯 ADD VARIOUS ITEMS TO LIBRARY
System.out.println("\n1. ADDING ITEMS TO LIBRARY:");
Book book1 = new Book("The Great Gatsby", "F. Scott Fitzgerald", "ISBN-001", 218);
Book book2 = new Book("To Kill a Mockingbird", "Harper Lee", "ISBN-002", 324);
DVD dvd1 = new DVD("Inception", "Christopher Nolan", "DVD-001", 148);
DVD dvd2 = new DVD("The Shawshank Redemption", "Frank Darabont", "DVD-002", 142);
Audiobook audio1 = new Audiobook("The Hobbit", "J.R.R. Tolkien", "AUDIO-001", 682, "Rob Inglis");
cityLibrary.addItem(book1);
cityLibrary.addItem(book2);
cityLibrary.addItem(dvd1);
cityLibrary.addItem(dvd2);
cityLibrary.addItem(audio1);
// 🎯 DISPLAY ALL ITEMS
cityLibrary.displayAllItems();
// 🎯 CHECKOUT OPERATIONS
System.out.println("\n2. CHECKOUT OPERATIONS:");
cityLibrary.checkoutItem("ISBN-001", "Alice Johnson");
cityLibrary.checkoutItem("DVD-001", "Bob Smith");
cityLibrary.checkoutItem("AUDIO-001", "Carol Davis");
// 🎯 SEARCH FUNCTIONALITY
System.out.println("\n3. SEARCH FUNCTIONALITY:");
cityLibrary.searchByAuthor("Tolkien");
cityLibrary.searchByAuthor("Nolan");
// 🎯 ITEM-SPECIFIC OPERATIONS
System.out.println("\n4. ITEM-SPECIFIC OPERATIONS:");
book1.readSample();
dvd1.playTrailer();
audio1.playSample();
// 🎯 POLYMORPHISM WITH DEFAULT METHODS
System.out.println("\n5. POLYMORPHIC PROCESSING:");
LibraryItem[] items = {book1, book2, dvd1, dvd2, audio1};
for (LibraryItem item : items) {
System.out.println("\n--- Processing " + item.getClass().getSimpleName() + " ---");
item.displayBasicInfo(); // Each calls appropriate version
if (item instanceof Book) {
((Book) item).readSample();
} else if (item instanceof DVD) {
((DVD) item).playTrailer();
} else if (item instanceof Audiobook) {
((Audiobook) item).playSample();
}
}
// 🎯 BENEFITS IN REAL-WORLD SYSTEMS
System.out.println("\n6. REAL-WORLD BENEFITS:");
System.out.println("βœ… Common Operations: checkout/checkin logic in one place");
System.out.println("βœ… Flexible Implementation: Each item type can customize behavior");
System.out.println("βœ… Backward Compatible: Can add new item types without changes");
System.out.println("βœ… Consistent API: All library items have same basic operations");
System.out.println("βœ… Reduced Code Duplication: Common logic in interface");
}
}

Output:

=== REAL-WORLD LIBRARY SYSTEM WITH DEFAULT METHODS ===
=== LIBRARY RULES ===
1. Loan period: 2 weeks
2. Maximum 10 items per borrower
3. Late fee: $0.25 per day
πŸ›οΈ Library created: City Public Library
1. ADDING ITEMS TO LIBRARY:
βž• Added to library: The Great Gatsby
βž• Added to library: To Kill a Mockingbird
βž• Added to library: Inception
βž• Added to library: The Shawshank Redemption
βž• Added to library: The Hobbit
=== CITY PUBLIC LIBRARY CATALOG ===
πŸ“š The Great Gatsby by F. Scott Fitzgerald
ID: ISBN-001 | Available: true
---
πŸ“š To Kill a Mockingbird by Harper Lee
ID: ISBN-002 | Available: true
---
πŸ“š Inception by Christopher Nolan
ID: DVD-001 | Available: true
---
πŸ“š The Shawshank Redemption by Frank Darabont
ID: DVD-002 | Available: true
---
🎧 The Hobbit by J.R.R. Tolkien
Narrated by: Rob Inglis
Duration: 682 minutes
ID: AUDIO-001 | Available: true
---
2. CHECKOUT OPERATIONS:
πŸ“– The Great Gatsby checked out to: Alice Johnson
Due date: 2024-01-14
πŸ“€ Inception DVD checked out to: Bob Smith
Due date: 2024-01-07
Duration: 148 minutes
πŸ“– The Hobbit checked out to: Carol Davis
Due date: 2024-01-14
3. SEARCH FUNCTIONALITY:
πŸ” Search results for author: Tolkien
🎧 The Hobbit by J.R.R. Tolkien
Narrated by: Rob Inglis
Duration: 682 minutes
ID: AUDIO-001 | Available: false
πŸ” Search results for author: Nolan
πŸ“š Inception by Christopher Nolan
ID: DVD-001 | Available: false
4. ITEM-SPECIFIC OPERATIONS:
πŸ“– Reading sample of: The Great Gatsby
Pages: 218
🎬 Playing trailer for: Inception
🎧 Playing sample of: The Hobbit
Narrated by: Rob Inglis
5. POLYMORPHIC PROCESSING:
--- Processing Book ---
πŸ“š The Great Gatsby by F. Scott Fitzgerald
ID: ISBN-001 | Available: false
πŸ“– Reading sample of: The Great Gatsby
Pages: 218
--- Processing Book ---
πŸ“š To Kill a Mockingbird by Harper Lee
ID: ISBN-002 | Available: true
πŸ“– Reading sample of: To Kill a Mockingbird
Pages: 324
--- Processing DVD ---
πŸ“š Inception by Christopher Nolan
ID: DVD-001 | Available: false
🎬 Playing trailer for: Inception
--- Processing DVD ---
πŸ“š The Shawshank Redemption by Frank Darabont
ID: DVD-002 | Available: true
🎬 Playing trailer for: The Shawshank Redemption
--- Processing Audiobook ---
🎧 The Hobbit by J.R.R. Tolkien
Narrated by: Rob Inglis
Duration: 682 minutes
ID: AUDIO-001 | Available: false
🎧 Playing sample of: The Hobbit
Narrated by: Rob Inglis
6. REAL-WORLD BENEFITS:
βœ… Common Operations: checkout/checkin logic in one place
βœ… Flexible Implementation: Each item type can customize behavior
βœ… Backward Compatible: Can add new item types without changes
βœ… Consistent API: All library items have same basic operations
βœ… Reduced Code Duplication: Common logic in interface

Example 3: Multiple Inheritance and Diamond Problem

// 🎯 INTERFACE 1: FLYABLE
interface Flyable {
default void fly() {
System.out.println("✈️ Flying through the air...");
}
default void takeOff() {
System.out.println("πŸ›« Taking off from ground...");
}
default void land() {
System.out.println("πŸ›¬ Landing safely...");
}
// 🎯 ABSTRACT METHOD
int getMaxAltitude();
}
// 🎯 INTERFACE 2: SWIMMABLE
interface Swimmable {
default void swim() {
System.out.println("🏊 Swimming in water...");
}
default void dive() {
System.out.println("🀿 Diving underwater...");
}
default void surface() {
System.out.println("🌊 Surfacing from water...");
}
// 🎯 ABSTRACT METHOD
int getMaxDepth();
}
// 🎯 INTERFACE 3: WALKABLE
interface Walkable {
default void walk() {
System.out.println("🚢 Walking on ground...");
}
default void run() {
System.out.println("πŸƒ Running fast...");
}
// 🎯 ABSTRACT METHOD
int getMaxSpeed();
}
// 🎯 INTERFACE EXTENDING OTHERS (MULTIPLE INHERITANCE)
interface Amphibious extends Swimmable, Walkable {
// 🎯 CONFLICT RESOLUTION: Both Swimmable and Walkable have move(), need to resolve
default void move() {
System.out.println("🐸 Amphibious creature moving... can walk or swim!");
}
// 🎯 OVERRIDE DEFAULT METHOD FROM PARENT INTERFACE
@Override
default void swim() {
System.out.println("🐸 Amphibious swimming with webbed feet...");
}
// 🎯 NEW DEFAULT METHOD
default void adaptToEnvironment() {
System.out.println("🐸 Adapting to current environment...");
}
}
// 🎯 CLASS IMPLEMENTING MULTIPLE INTERFACES
class Duck implements Flyable, Swimmable, Walkable {
private String name;
public Duck(String name) {
this.name = name;
System.out.println("πŸ¦† Duck created: " + name);
}
// 🎯 MUST IMPLEMENT ABSTRACT METHODS FROM ALL INTERFACES
@Override
public int getMaxAltitude() {
return 1000; // meters
}
@Override
public int getMaxDepth() {
return 5; // meters
}
@Override
public int getMaxSpeed() {
return 10; // km/h
}
// 🎯 OVERRIDE DEFAULT METHOD (OPTIONAL)
@Override
public void swim() {
System.out.println("πŸ¦† " + name + " is paddling in water...");
}
// 🎯 DUCK-SPECIFIC METHOD
public void quack() {
System.out.println("πŸ¦† " + name + " says: Quack! Quack!");
}
}
// 🎯 CLASS IMPLEMENTING AMPHIBIOUS INTERFACE
class Frog implements Amphibious {
private String name;
public Frog(String name) {
this.name = name;
System.out.println("🐸 Frog created: " + name);
}
// 🎯 MUST IMPLEMENT ABSTRACT METHODS
@Override
public int getMaxDepth() {
return 3; // meters
}
@Override
public int getMaxSpeed() {
return 8; // km/h
}
// 🎯 FROG-SPECIFIC METHOD
public void jump() {
System.out.println("🐸 " + name + " is jumping high!");
}
// 🎯 OVERRIDE DEFAULT METHOD
@Override
public void adaptToEnvironment() {
System.out.println("🐸 " + name + " changing color to match environment...");
}
}
// 🎯 CLASS WITH CONFLICT RESOLUTION
class FlyingFish implements Flyable, Swimmable {
private String name;
public FlyingFish(String name) {
this.name = name;
System.out.println("🐠 Flying Fish created: " + name);
}
// 🎯 MUST IMPLEMENT ABSTRACT METHODS
@Override
public int getMaxAltitude() {
return 50; // meters (can glide above water)
}
@Override
public int getMaxDepth() {
return 100; // meters
}
// 🎯 RESOLVING CONFLICT: Both interfaces might have conflicting methods
// In this case, no conflict because methods have different names
// 🎯 OVERRIDE FLY METHOD FOR FISH-SPECIFIC BEHAVIOR
@Override
public void fly() {
System.out.println("🐠 " + name + " is gliding above water surface...");
}
// 🎯 FISH-SPECIFIC METHOD
public void school() {
System.out.println("🐠 " + name + " is swimming in a school with other fish");
}
}
// 🎯 DEMONSTRATING DIAMOND PROBLEM RESOLUTION
interface A {
default void doSomething() {
System.out.println("A: Doing something...");
}
}
interface B extends A {
@Override
default void doSomething() {
System.out.println("B: Overriding A's method...");
}
}
interface C extends A {
@Override
default void doSomething() {
System.out.println("C: Overriding A's method differently...");
}
}
// 🎯 CLASS FACING DIAMOND PROBLEM - MUST RESOLVE EXPLICITLY
class D implements B, C {
// ❌ COMPILATION ERROR: class D inherits unrelated defaults for doSomething() from B and C
// 🎯 MUST OVERRIDE TO RESOLVE CONFLICT
@Override
public void doSomething() {
// Choose which implementation to use, or provide new one
System.out.println("D: Resolving conflict by providing new implementation");
B.super.doSomething(); // Can call B's version explicitly
}
}
public class MultipleInheritanceDemo {
public static void main(String[] args) {
System.out.println("=== MULTIPLE INHERITANCE AND DIAMOND PROBLEM ===");
// 🎯 CREATING CREATURES WITH MULTIPLE CAPABILITIES
Duck duck = new Duck("Daffy");
Frog frog = new Frog("Kermit");
FlyingFish flyingFish = new FlyingFish("Skippy");
// 🎯 DEMONSTRATING MULTIPLE BEHAVIORS
System.out.println("\n1. DUCK CAPABILITIES:");
System.out.println("--- Flying ---");
duck.takeOff();
duck.fly();
duck.land();
System.out.println("Max altitude: " + duck.getMaxAltitude() + "m");
System.out.println("--- Swimming ---");
duck.swim(); // Overridden version
duck.dive();
System.out.println("Max depth: " + duck.getMaxDepth() + "m");
System.out.println("--- Walking ---");
duck.walk();
duck.run();
System.out.println("Max speed: " + duck.getMaxSpeed() + "km/h");
duck.quack();
// 🎯 FROG WITH AMPHIBIOUS CAPABILITIES
System.out.println("\n2. FROG CAPABILITIES:");
frog.walk();
frog.swim(); // From Amphibious interface (overridden)
frog.move(); // From Amphibious interface
frog.adaptToEnvironment(); // Overridden version
frog.jump();
// 🎯 FLYING FISH CAPABILITIES
System.out.println("\n3. FLYING FISH CAPABILITIES:");
flyingFish.fly(); // Overridden version
flyingFish.swim();
flyingFish.dive();
flyingFish.school();
// 🎯 POLYMORPHISM WITH MULTIPLE INTERFACES
System.out.println("\n4. POLYMORPHIC PROCESSING:");
Flyable[] flyers = {duck, flyingFish};
Swimmable[] swimmers = {duck, frog, flyingFish};
Walkable[] walkers = {duck, frog};
System.out.println("--- Flyers ---");
for (Flyable flyer : flyers) {
flyer.fly();
System.out.println("   Max altitude: " + flyer.getMaxAltitude() + "m");
}
System.out.println("--- Swimmers ---");
for (Swimmable swimmer : swimmers) {
swimmer.swim();
System.out.println("   Max depth: " + swimmer.getMaxDepth() + "m");
}
System.out.println("--- Walkers ---");
for (Walkable walker : walkers) {
walker.walk();
System.out.println("   Max speed: " + walker.getMaxSpeed() + "km/h");
}
// 🎯 DIAMOND PROBLEM RESOLUTION
System.out.println("\n5. DIAMOND PROBLEM RESOLUTION:");
D d = new D();
d.doSomething();
// 🎯 BENEFITS AND CHALLENGES
System.out.println("\n6. MULTIPLE INHERITANCE BENEFITS:");
System.out.println("βœ… Code Reuse: Multiple behaviors from different interfaces");
System.out.println("βœ… Flexibility: Mix and match capabilities");
System.out.println("βœ… No Diamond Problem: Compile-time resolution required");
System.out.println("βœ… Clear Contracts: Each interface defines specific behavior");
System.out.println("\n7. RESOLUTION RULES:");
System.out.println("Rule 1: Class wins over interface");
System.out.println("Rule 2: Most specific interface wins");
System.out.println("Rule 3: Explicit override required for conflicts");
}
}

Output:

=== MULTIPLE INHERITANCE AND DIAMOND PROBLEM ===
πŸ¦† Duck created: Daffy
🐸 Frog created: Kermit
🐠 Flying Fish created: Skippy
1. DUCK CAPABILITIES:
--- Flying ---
πŸ›« Taking off from ground...
✈️ Flying through the air...
πŸ›¬ Landing safely...
Max altitude: 1000m
--- Swimming ---
πŸ¦† Daffy is paddling in water...
🀿 Diving underwater...
Max depth: 5m
--- Walking ---
🚢 Walking on ground...
πŸƒ Running fast...
Max speed: 10km/h
πŸ¦† Daffy says: Quack! Quack!
2. FROG CAPABILITIES:
🚢 Walking on ground...
🐸 Amphibious swimming with webbed feet...
🐸 Amphibious creature moving... can walk or swim!
🐸 Kermit changing color to match environment...
🐸 Kermit is jumping high!
3. FLYING FISH CAPABILITIES:
🐠 Skippy is gliding above water surface...
🏊 Swimming in water...
🀿 Diving underwater...
🐠 Skippy is swimming in a school with other fish
4. POLYMORPHIC PROCESSING:
--- Flyers ---
✈️ Flying through the air...
Max altitude: 1000m
🐠 Skippy is gliding above water surface...
Max altitude: 50m
--- Swimmers ---
πŸ¦† Daffy is paddling in water...
Max depth: 5m
🐸 Amphibious swimming with webbed feet...
Max depth: 3m
🏊 Swimming in water...
Max depth: 100m
--- Walkers ---
🚢 Walking on ground...
Max speed: 10km/h
🚢 Walking on ground...
Max speed: 8km/h
5. DIAMOND PROBLEM RESOLUTION:
D: Resolving conflict by providing new implementation
B: Overriding A's method...
6. MULTIPLE INHERITANCE BENEFITS:
βœ… Code Reuse: Multiple behaviors from different interfaces
βœ… Flexibility: Mix and match capabilities
βœ… No Diamond Problem: Compile-time resolution required
βœ… Clear Contracts: Each interface defines specific behavior
7. RESOLUTION RULES:
Rule 1: Class wins over interface
Rule 2: Most specific interface wins
Rule 3: Explicit override required for conflicts

Example 4: Advanced Patterns and Best Practices

import java.util.function.Predicate;
import java.util.ArrayList;
import java.util.List;
// 🎯 REPOSITORY PATTERN WITH DEFAULT METHODS
interface Repository<T> {
// 🎯 CRUD OPERATIONS (ABSTRACT)
void save(T entity);
void delete(T entity);
T findById(String id);
List<T> findAll();
// 🎯 DEFAULT METHODS FOR COMMON OPERATIONS
default boolean exists(String id) {
return findById(id) != null;
}
default long count() {
return findAll().size();
}
default void saveAll(List<T> entities) {
for (T entity : entities) {
save(entity);
}
System.out.println("πŸ’Ύ Saved " + entities.size() + " entities");
}
default void deleteAll() {
List<T> allEntities = findAll();
for (T entity : allEntities) {
delete(entity);
}
System.out.println("πŸ—‘οΈ Deleted " + allEntities.size() + " entities");
}
default List<T> filter(Predicate<T> predicate) {
List<T> result = new ArrayList<>();
for (T entity : findAll()) {
if (predicate.test(entity)) {
result.add(entity);
}
}
return result;
}
// 🎯 STATIC METHOD FOR VALIDATION
static <T> boolean isValidId(String id) {
return id != null && !id.trim().isEmpty() && id.length() >= 1;
}
// 🎯 DEFAULT METHOD WITH FUNCTIONAL INTERFACE
default void processAll(java.util.function.Consumer<T> processor) {
for (T entity : findAll()) {
processor.accept(entity);
}
}
}
// 🎯 USER ENTITY
class User {
private String id;
private String name;
private String email;
private boolean active;
public User(String id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
this.active = true;
}
// 🎯 GETTERS AND SETTERS
public String getId() { return id; }
public String getName() { return name; }
public String getEmail() { return email; }
public boolean isActive() { return active; }
public void setActive(boolean active) { this.active = active; }
@Override
public String toString() {
return "User{id='" + id + "', name='" + name + "', email='" + email + "', active=" + active + "}";
}
}
// 🎯 USER REPOSITORY IMPLEMENTATION
class UserRepository implements Repository<User> {
private List<User> users = new ArrayList<>();
private static int nextId = 1;
@Override
public void save(User user) {
if (user.getId() == null) {
user = new User("USER-" + (nextId++), user.getName(), user.getEmail());
}
// Remove existing user with same ID
users.removeIf(u -> u.getId().equals(user.getId()));
users.add(user);
System.out.println("βœ… Saved user: " + user.getName());
}
@Override
public void delete(User user) {
if (users.remove(user)) {
System.out.println("❌ Deleted user: " + user.getName());
}
}
@Override
public User findById(String id) {
return users.stream()
.filter(user -> user.getId().equals(id))
.findFirst()
.orElse(null);
}
@Override
public List<User> findAll() {
return new ArrayList<>(users);
}
// 🎯 OVERRIDE DEFAULT METHOD FOR OPTIMIZATION
@Override
public boolean exists(String id) {
return users.stream().anyMatch(user -> user.getId().equals(id));
}
// 🎯 USER-SPECIFIC METHODS
public List<User> findActiveUsers() {
return filter(User::isActive);
}
public List<User> findByName(String name) {
return filter(user -> user.getName().toLowerCase().contains(name.toLowerCase()));
}
public void deactivateAll() {
processAll(user -> user.setActive(false));
System.out.println("πŸ”’ All users deactivated");
}
}
// 🎯 PRODUCT ENTITY
class Product {
private String id;
private String name;
private double price;
private int stock;
public Product(String id, String name, double price, int stock) {
this.id = id;
this.name = name;
this.price = price;
this.stock = stock;
}
public String getId() { return id; }
public String getName() { return name; }
public double getPrice() { return price; }
public int getStock() { return stock; }
public void setStock(int stock) { this.stock = stock; }
@Override
public String toString() {
return String.format("Product{id='%s', name='%s', price=$%.2f, stock=%d}", 
id, name, price, stock);
}
}
// 🎯 PRODUCT REPOSITORY
class ProductRepository implements Repository<Product> {
private List<Product> products = new ArrayList<>();
@Override
public void save(Product product) {
products.removeIf(p -> p.getId().equals(product.getId()));
products.add(product);
System.out.println("βœ… Saved product: " + product.getName());
}
@Override
public void delete(Product product) {
if (products.remove(product)) {
System.out.println("❌ Deleted product: " + product.getName());
}
}
@Override
public Product findById(String id) {
return products.stream()
.filter(product -> product.getId().equals(id))
.findFirst()
.orElse(null);
}
@Override
public List<Product> findAll() {
return new ArrayList<>(products);
}
// 🎯 PRODUCT-SPECIFIC METHODS USING DEFAULT METHODS
public List<Product> findOutOfStock() {
return filter(product -> product.getStock() == 0);
}
public List<Product> findByPriceRange(double min, double max) {
return filter(product -> product.getPrice() >= min && product.getPrice() <= max);
}
public double calculateTotalInventoryValue() {
final double[] total = {0};
processAll(product -> total[0] += product.getPrice() * product.getStock());
return total[0];
}
}
public class AdvancedPatternsDemo {
public static void main(String[] args) {
System.out.println("=== ADVANCED PATTERNS WITH DEFAULT METHODS ===");
// 🎯 USER REPOSITORY DEMONSTRATION
System.out.println("\n1. USER REPOSITORY:");
UserRepository userRepo = new UserRepository();
// Create users
User user1 = new User(null, "Alice Johnson", "[email protected]");
User user2 = new User(null, "Bob Smith", "[email protected]");
User user3 = new User(null, "Carol Davis", "[email protected]");
// Save users using default method
userRepo.saveAll(List.of(user1, user2, user3));
// Demonstrate default methods
System.out.println("\n--- Default Method Demonstrations ---");
System.out.println("Total users: " + userRepo.count());
System.out.println("User USER-1 exists: " + userRepo.exists("USER-1"));
// Find active users (using overridden default method)
System.out.println("\nActive users:");
userRepo.findActiveUsers().forEach(System.out::println);
// Deactivate all users
userRepo.deactivateAll();
System.out.println("Active users after deactivation: " + userRepo.findActiveUsers().size());
// 🎯 PRODUCT REPOSITORY DEMONSTRATION
System.out.println("\n2. PRODUCT REPOSITORY:");
ProductRepository productRepo = new ProductRepository();
// Create products
Product p1 = new Product("P1", "Laptop", 999.99, 10);
Product p2 = new Product("P2", "Mouse", 29.99, 0);
Product p3 = new Product("P3", "Keyboard", 79.99, 5);
Product p4 = new Product("P4", "Monitor", 299.99, 3);
productRepo.saveAll(List.of(p1, p2, p3, p4));
// Demonstrate repository operations
System.out.println("\n--- Product Operations ---");
System.out.println("Total products: " + productRepo.count());
System.out.println("\nOut of stock products:");
productRepo.findOutOfStock().forEach(System.out::println);
System.out.println("\nProducts between $50 and $200:");
productRepo.findByPriceRange(50, 200).forEach(System.out::println);
System.out.printf("\nTotal inventory value: $%.2f%n", productRepo.calculateTotalInventoryValue());
// 🎯 STATIC METHOD USAGE
System.out.println("\n3. STATIC METHOD VALIDATION:");
System.out.println("Is 'USER-1' valid ID: " + Repository.isValidId("USER-1"));
System.out.println("Is '' valid ID: " + Repository.isValidId(""));
System.out.println("Is null valid ID: " + Repository.isValidId(null));
// 🎯 POLYMORPHISM WITH REPOSITORIES
System.out.println("\n4. POLYMORPHIC REPOSITORY PROCESSING:");
Repository<?>[] repositories = {userRepo, productRepo};
for (Repository<?> repo : repositories) {
System.out.println("\n--- " + repo.getClass().getSimpleName() + " ---");
System.out.println("Entity count: " + repo.count());
System.out.println("Sample entities:");
repo.findAll().stream().limit(2).forEach(System.out::println);
}
// 🎯 BENEFITS AND PATTERNS
System.out.println("\n5. DESIGN PATTERNS ENABLED:");
System.out.println("βœ… Repository Pattern: Common data access operations");
System.out.println("βœ… Template Method: Default implementations with hooks");
System.out.println("βœ… Strategy Pattern: Filtering with predicates");
System.out.println("βœ… Decorator Pattern: Layering functionality");
System.out.println("\n6. BEST PRACTICES:");
System.out.println("πŸ”Ή Use default methods for common implementation");
System.out.println("πŸ”Ή Keep default methods simple and focused");
System.out.println("πŸ”Ή Use static methods for utility functions");
System.out.println("πŸ”Ή Override default methods when optimization needed");
System.out.println("πŸ”Ή Document default method behavior clearly");
// 🎯 CLEANUP
System.out.println("\n7. CLEANUP:");
userRepo.deleteAll();
productRepo.deleteAll();
System.out.println("All repositories cleared");
}
}

Output:

=== ADVANCED PATTERNS WITH DEFAULT METHODS ===
1. USER REPOSITORY:
πŸ’Ύ Saved 3 entities
βœ… Saved user: Alice Johnson
βœ… Saved user: Bob Smith
βœ… Saved user: Carol Davis
--- Default Method Demonstrations ---
Total users: 3
User USER-1 exists: true
Active users:
User{id='USER-1', name='Alice Johnson', email='[email protected]', active=true}
User{id='USER-2', name='Bob Smith', email='[email protected]', active=true}
User{id='USER-3', name='Carol Davis', email='[email protected]', active=true}
πŸ”’ All users deactivated
Active users after deactivation: 0
2. PRODUCT REPOSITORY:
πŸ’Ύ Saved 4 entities
βœ… Saved product: Laptop
βœ… Saved product: Mouse
βœ… Saved product: Keyboard
βœ… Saved product: Monitor
--- Product Operations ---
Total products: 4
Out of stock products:
Product{id='P2', name='Mouse', price=$29.99, stock=0}
Products between $50 and $200:
Product{id='P3', name='Keyboard', price=$79.99, stock=5}
Total inventory value: $12569.86
3. STATIC METHOD VALIDATION:
Is 'USER-1' valid ID: true
Is '' valid ID: false
Is null valid ID: false
4. POLYMORPHIC REPOSITORY PROCESSING:
--- UserRepository ---
Entity count: 3
Sample entities:
User{id='USER-1', name='Alice Johnson', email='[email protected]', active=false}
User{id='USER-2', name='Bob Smith', email='[email protected]', active=false}
--- ProductRepository ---
Entity count: 4
Sample entities:
Product{id='P1', name='Laptop', price=$999.99, stock=10}
Product{id='P2', name='Mouse', price=$29.99, stock=0}
5. DESIGN PATTERNS ENABLED:
βœ… Repository Pattern: Common data access operations
βœ… Template Method: Default implementations with hooks
βœ… Strategy Pattern: Filtering with predicates
βœ… Decorator Pattern: Layering functionality
6. BEST PRACTICES:
πŸ”Ή Use default methods for common implementation
πŸ”Ή Keep default methods simple and focused
πŸ”Ή Use static methods for utility functions
πŸ”Ή Override default methods when optimization needed
πŸ”Ή Document default method behavior clearly
7. CLEANUP:
πŸ—‘οΈ Deleted 3 entities
πŸ—‘οΈ Deleted 4 entities
All repositories cleared

Key Rules and Resolution

Default Method Rules:

  1. Class wins over interface
  2. Most specific interface wins
  3. Explicit override required for conflicts
  4. Can call parent with InterfaceName.super.methodName()

Diamond Problem Resolution:

interface A { default void foo() {} }
interface B extends A { default void foo() {} }
interface C extends A { default void foo() {} }
class D implements B, C {
// ❌ COMPILATION ERROR - must override
@Override
public void foo() {
B.super.foo(); // Choose explicitly
}
}

Best Practices

  1. Use for backward compatibility - add methods to existing interfaces
  2. Keep implementations simple - avoid complex logic in defaults
  3. Document behavior - clearly state what default methods do
  4. Use static methods for utility functions
  5. Override when needed - provide class-specific implementations
  6. Avoid state - default methods shouldn't maintain state
  7. Consider composition over complex interface hierarchies

Common Use Cases

βœ… Perfect for:

  • Utility methods in collections
  • Adapter methods in functional interfaces
  • Common implementation in frameworks
  • Backward compatibility in APIs
  • Template methods with hooks

❌ Avoid for:

  • Complex business logic
  • State-dependent operations
  • Performance-critical code
  • When abstraction is unclear

Conclusion

Default methods revolutionized Java interfaces by:

  • βœ… Enabling interface evolution without breaking changes
  • βœ… Providing common implementation in one place
  • βœ… Supporting multiple inheritance of behavior
  • βœ… Enabling powerful patterns like repositories and templates
  • βœ… Maintaining backward compatibility with existing code

Key Takeaways:

  1. default keyword enables method implementations in interfaces
  2. Classes inherit default methods automatically
  3. Can be overridden by implementing classes
  4. Solve diamond problem with explicit overrides
  5. Enable rich interfaces with common functionality

Remember: Default methods are like having a "starter kit" in your interfaces - implementing classes get useful functionality out of the box but can customize it as needed! πŸŽπŸš€

Now you're equipped to design flexible, evolvable interfaces that provide real value to implementing classes!

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper