Introduction
Imagine you're a superhero who can inherit powers from multiple sources: flying like Superman, super strength like Hulk, and web-slinging like Spider-Man. In the real world, you can't inherit from multiple parents, but in Java, interfaces let your classes "inherit" behaviors from multiple sources!
Multiple Inheritance via Interfaces is Java's clever solution to the "diamond problem" that plagues other languages. While Java doesn't allow multiple inheritance of classes, it fully supports multiple inheritance of interfaces, giving you the power of multiple behaviors without the complexity.
What is Multiple Inheritance via Interfaces?
Multiple inheritance via interfaces allows a class to implement multiple interfaces, thereby inheriting abstract methods from all of them. This enables a class to have multiple "types" and behaviors from different interface hierarchies.
Key Characteristics:
- β A class can implement multiple interfaces
- β No diamond problem - interfaces don't have state
- β Provides multiple "is-a" relationships
- β Enables rich, complex behaviors
- β Compile-time safety - all methods must be implemented
Code Explanation with Examples
Example 1: Basic Multiple Interface Implementation
// Interface 1 - Flying capability
interface Flyable {
void fly();
int getMaxAltitude();
}
// Interface 2 - Swimming capability
interface Swimmable {
void swim();
int getMaxDepth();
}
// Interface 3 - Running capability
interface Runnable {
void run();
double getMaxSpeed();
}
// Class implementing MULTIPLE interfaces
class SuperDuck implements Flyable, Swimmable, Runnable {
private String name;
public SuperDuck(String name) {
this.name = name;
}
// Flyable interface implementation
@Override
public void fly() {
System.out.println(name + " is flying high in the sky!");
}
@Override
public int getMaxAltitude() {
return 1000; // meters
}
// Swimmable interface implementation
@Override
public void swim() {
System.out.println(name + " is swimming gracefully in the pond");
}
@Override
public int getMaxDepth() {
return 5; // meters
}
// Runnable interface implementation
@Override
public void run() {
System.out.println(name + " is running fast on land");
}
@Override
public double getMaxSpeed() {
return 20.5; // km/h
}
// SuperDuck specific method
public void showAllAbilities() {
System.out.println("=== " + name + "'s SUPER ABILITIES ===");
System.out.println("I can fly up to " + getMaxAltitude() + " meters");
System.out.println("I can swim up to " + getMaxDepth() + " meters deep");
System.out.println("I can run at " + getMaxSpeed() + " km/h");
}
}
public class BasicMultipleInterfaces {
public static void main(String[] args) {
System.out.println("=== BASIC MULTIPLE INTERFACE INHERITANCE ===");
SuperDuck superDuck = new SuperDuck("Mighty Duck");
// Use as Flyable
System.out.println("=== AS FLYABLE ===");
Flyable flyer = superDuck;
flyer.fly();
System.out.println("Max altitude: " + flyer.getMaxAltitude() + "m");
// Use as Swimmable
System.out.println("\n=== AS SWIMMABLE ===");
Swimmable swimmer = superDuck;
swimmer.swim();
System.out.println("Max depth: " + swimmer.getMaxDepth() + "m");
// Use as Runnable
System.out.println("\n=== AS RUNNABLE ===");
Runnable runner = superDuck;
runner.run();
System.out.println("Max speed: " + runner.getMaxSpeed() + " km/h");
// Use as SuperDuck (all capabilities)
System.out.println("\n=== AS SUPER DUCK ===");
superDuck.showAllAbilities();
// Array of different interface types containing same object
System.out.println("\n=== INTERFACE ARRAYS ===");
Object[] abilities = {flyer, swimmer, runner, superDuck};
for (Object ability : abilities) {
System.out.println(ability.getClass().getSimpleName() + " capability");
}
}
}
Output:
=== BASIC MULTIPLE INTERFACE INHERITANCE === === AS FLYABLE === Mighty Duck is flying high in the sky! Max altitude: 1000m === AS SWIMMABLE === Mighty Duck is swimming gracefully in the pond Max depth: 5m === AS RUNNABLE === Mighty Duck is running fast on land Max speed: 20.5 km/h === AS SUPER DUCK === === Mighty Duck's SUPER ABILITIES === I can fly up to 1000 meters I can swim up to 5 meters deep I can run at 20.5 km/h === INTERFACE ARRAYS === SuperDuck capability SuperDuck capability SuperDuck capability SuperDuck capability
Example 2: Real-World Employee System with Multiple Roles
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
// Interface 1 - Basic employee
interface Employee {
String getName();
double getSalary();
String getDepartment();
}
// Interface 2 - Manager capabilities
interface Manager {
void conductMeeting();
void assignTask(String task, Employee employee);
List<Employee> getTeamMembers();
}
// Interface 3 - Developer capabilities
interface Developer {
void writeCode();
void debugCode();
String getProgrammingLanguage();
}
// Interface 4 - Trainer capabilities
interface Trainer {
void conductTraining(String topic);
List<String> getExpertiseAreas();
}
// Interface 5 - Report generator
interface ReportGenerator {
String generateReport();
void exportToPDF();
}
// Class implementing MULTIPLE roles
class TechLead implements Employee, Manager, Developer, Trainer, ReportGenerator {
private String name;
private double salary;
private String department;
private String programmingLanguage;
private List<Employee> teamMembers;
private List<String> expertiseAreas;
public TechLead(String name, double salary, String programmingLanguage) {
this.name = name;
this.salary = salary;
this.department = "Engineering";
this.programmingLanguage = programmingLanguage;
this.teamMembers = new ArrayList<>();
this.expertiseAreas = new ArrayList<>();
// Add some default expertise
expertiseAreas.add("Java Programming");
expertiseAreas.add("System Design");
expertiseAreas.add("Agile Methodology");
}
// Employee interface methods
@Override
public String getName() {
return name;
}
@Override
public double getSalary() {
return salary;
}
@Override
public String getDepartment() {
return department;
}
// Manager interface methods
@Override
public void conductMeeting() {
System.out.println(name + " is conducting a team meeting with " +
teamMembers.size() + " team members");
}
@Override
public void assignTask(String task, Employee employee) {
System.out.println(name + " assigned task '" + task +
"' to " + employee.getName());
}
@Override
public List<Employee> getTeamMembers() {
return new ArrayList<>(teamMembers);
}
public void addTeamMember(Employee employee) {
teamMembers.add(employee);
System.out.println("Added " + employee.getName() + " to " + name + "'s team");
}
// Developer interface methods
@Override
public void writeCode() {
System.out.println(name + " is writing high-quality " +
programmingLanguage + " code");
}
@Override
public void debugCode() {
System.out.println(name + " is debugging complex system issues");
}
@Override
public String getProgrammingLanguage() {
return programmingLanguage;
}
// Trainer interface methods
@Override
public void conductTraining(String topic) {
System.out.println(name + " is conducting training on: " + topic);
}
@Override
public List<String> getExpertiseAreas() {
return new ArrayList<>(expertiseAreas);
}
public void addExpertise(String expertise) {
expertiseAreas.add(expertise);
System.out.println("Added new expertise: " + expertise);
}
// ReportGenerator interface methods
@Override
public String generateReport() {
return String.format(
"Tech Lead Report:\n" +
"Name: %s\n" +
"Department: %s\n" +
"Team Size: %d\n" +
"Primary Language: %s\n" +
"Expertise Areas: %s\n" +
"Generated on: %s",
name, department, teamMembers.size(),
programmingLanguage, expertiseAreas, LocalDate.now()
);
}
@Override
public void exportToPDF() {
System.out.println("Exporting report to PDF format...");
System.out.println(generateReport());
System.out.println("PDF export completed!");
}
// TechLead specific method
public void performAllDuties() {
System.out.println("=== " + name + "'s DAILY DUTIES ===");
conductMeeting();
writeCode();
conductTraining("Advanced Java Patterns");
assignTask("Code review", teamMembers.isEmpty() ? null : teamMembers.get(0));
System.out.println("---");
exportToPDF();
}
}
// Regular Developer class
class JuniorDeveloper implements Employee, Developer {
private String name;
private double salary;
private String department;
private String programmingLanguage;
public JuniorDeveloper(String name, double salary, String programmingLanguage) {
this.name = name;
this.salary = salary;
this.department = "Engineering";
this.programmingLanguage = programmingLanguage;
}
// Employee interface
@Override public String getName() { return name; }
@Override public double getSalary() { return salary; }
@Override public String getDepartment() { return department; }
// Developer interface
@Override
public void writeCode() {
System.out.println(name + " is learning to write " + programmingLanguage + " code");
}
@Override
public void debugCode() {
System.out.println(name + " is debugging with help from seniors");
}
@Override
public String getProgrammingLanguage() {
return programmingLanguage;
}
}
public class EmployeeRolesDemo {
public static void main(String[] args) {
System.out.println("=== MULTIPLE ROLES EMPLOYEE SYSTEM ===");
// Create a TechLead with multiple roles
TechLead techLead = new TechLead("Alice Johnson", 120000, "Java");
// Create team members
JuniorDeveloper dev1 = new JuniorDeveloper("Bob Smith", 60000, "Java");
JuniorDeveloper dev2 = new JuniorDeveloper("Carol Davis", 65000, "Python");
// Build team
techLead.addTeamMember(dev1);
techLead.addTeamMember(dev2);
System.out.println();
// Demonstrate different roles
System.out.println("=== EMPLOYEE ROLE ===");
displayEmployeeInfo(techLead);
System.out.println("\n=== MANAGER ROLE ===");
demonstrateManager(techLead);
System.out.println("\n=== DEVELOPER ROLE ===");
demonstrateDeveloper(techLead);
System.out.println("\n=== TRAINER ROLE ===");
demonstrateTrainer(techLead);
System.out.println("\n=== REPORT GENERATOR ROLE ===");
demonstrateReportGenerator(techLead);
System.out.println("\n=== ALL ROLES COMBINED ===");
techLead.performAllDuties();
// Array of different interface types
System.out.println("\n=== MULTIPLE INTERFACE REFERENCES ===");
Object[] roles = {
(Employee) techLead,
(Manager) techLead,
(Developer) techLead,
(Trainer) techLead,
(ReportGenerator) techLead
};
for (Object role : roles) {
System.out.println("Role: " + role.getClass().getInterfaces()[0].getSimpleName());
}
}
// Methods that accept specific interface types
public static void displayEmployeeInfo(Employee employee) {
System.out.println("Name: " + employee.getName());
System.out.println("Salary: $" + employee.getSalary());
System.out.println("Department: " + employee.getDepartment());
}
public static void demonstrateManager(Manager manager) {
manager.conductMeeting();
System.out.println("Team size: " + manager.getTeamMembers().size());
}
public static void demonstrateDeveloper(Developer developer) {
developer.writeCode();
developer.debugCode();
System.out.println("Primary language: " + developer.getProgrammingLanguage());
}
public static void demonstrateTrainer(Trainer trainer) {
trainer.conductTraining("Java Best Practices");
System.out.println("Expertise areas: " + trainer.getExpertiseAreas());
}
public static void demonstrateReportGenerator(ReportGenerator generator) {
System.out.println(generator.generateReport());
}
}
Output:
=== MULTIPLE ROLES EMPLOYEE SYSTEM === Added Bob Smith to Alice Johnson's team Added Carol Davis to Alice Johnson's team === EMPLOYEE ROLE === Name: Alice Johnson Salary: $120000.0 Department: Engineering === MANAGER ROLE === Alice Johnson is conducting a team meeting with 2 team members Team size: 2 === DEVELOPER ROLE === Alice Johnson is writing high-quality Java code Alice Johnson is debugging complex system issues Primary language: Java === TRAINER ROLE === Alice Johnson is conducting training on: Java Best Practices Expertise areas: [Java Programming, System Design, Agile Methodology] === REPORT GENERATOR ROLE === Tech Lead Report: Name: Alice Johnson Department: Engineering Team Size: 2 Primary Language: Java Expertise Areas: [Java Programming, System Design, Agile Methodology] Generated on: 2024-01-15 === ALL ROLES COMBINED === === Alice Johnson's DAILY DUTIES === Alice Johnson is conducting a team meeting with 2 team members Alice Johnson is writing high-quality Java code Alice Johnson is conducting training on: Advanced Java Patterns Alice Johnson assigned task 'Code review' to Bob Smith --- Exporting report to PDF format... Tech Lead Report: Name: Alice Johnson Department: Engineering Team Size: 2 Primary Language: Java Expertise Areas: [Java Programming, System Design, Agile Methodology] Generated on: 2024-01-15 PDF export completed! === MULTIPLE INTERFACE REFERENCES === Role: Employee Role: Manager Role: Developer Role: Trainer Role: ReportGenerator
Example 3: Resolving Method Conflicts with Default Methods
// Interface with default method
interface Writer {
default void write() {
System.out.println("Writing generic content");
}
void setContent(String content);
}
// Another interface with same default method
interface Blogger {
default void write() {
System.out.println("Writing blog post");
}
void publish();
}
// Interface with different default method
interface Reporter {
default void write() {
System.out.println("Writing news report");
}
void investigate();
}
// β PROBLEM: Class won't compile due to conflicting default methods
/*
class ConflictWriter implements Writer, Blogger {
// Compilation error: class ConflictWriter inherits unrelated defaults for write()
}
*/
// β
SOLUTION 1: Override the conflicting method
class SmartWriter implements Writer, Blogger {
private String content;
@Override
public void write() {
// Choose which behavior to use, or create new one
System.out.println("Smart writing: " + content);
}
@Override
public void setContent(String content) {
this.content = content;
}
@Override
public void publish() {
System.out.println("Publishing to blog platform");
}
}
// β
SOLUTION 2: Explicitly choose which interface's default method to use
class NewsBlogger implements Writer, Blogger, Reporter {
private String content;
private String articleType;
// Explicitly choose which interface's default method to use
@Override
public void write() {
// Use Reporter's write method specifically
if ("news".equals(articleType)) {
// Can't call super.write() directly, so we mimic the behavior
System.out.println("Writing news report: " + content);
} else if ("blog".equals(articleType)) {
System.out.println("Writing blog post: " + content);
} else {
System.out.println("Writing: " + content);
}
}
// Alternative: Call specific interface's default method using super
public void writeAsBlogger() {
// Can't do this directly in overridden write() method
System.out.print("As Blogger: ");
System.out.println("Writing blog post: " + content);
}
public void writeAsReporter() {
System.out.print("As Reporter: ");
System.out.println("Writing news report: " + content);
}
@Override
public void setContent(String content) {
this.content = content;
}
@Override
public void publish() {
System.out.println("Publishing content: " + content);
}
@Override
public void investigate() {
System.out.println("Investigating story for news report");
}
public void setArticleType(String articleType) {
this.articleType = articleType;
}
}
// Interface with no default method conflict
interface Editor {
void edit(); // No default method, so no conflict
}
// Class with no conflicts
class PeacefulWriter implements Writer, Editor {
private String content;
// No need to override write() - no conflict
// Uses Writer's default write() method
@Override
public void setContent(String content) {
this.content = content;
}
@Override
public void edit() {
System.out.println("Editing content: " + content);
}
}
public class DefaultMethodConflicts {
public static void main(String[] args) {
System.out.println("=== DEFAULT METHOD CONFLICTS AND SOLUTIONS ===");
// Solution 1: Override the method
System.out.println("\n=== SOLUTION 1: OVERRIDE ===");
SmartWriter smart = new SmartWriter();
smart.setContent("Hello World");
smart.write();
smart.publish();
// Solution 2: Explicit behavior selection
System.out.println("\n=== SOLUTION 2: EXPLICIT SELECTION ===");
NewsBlogger newsBlogger = new NewsBlogger();
newsBlogger.setContent("Breaking News!");
newsBlogger.setArticleType("news");
newsBlogger.write();
newsBlogger.setArticleType("blog");
newsBlogger.write();
newsBlogger.writeAsBlogger();
newsBlogger.writeAsReporter();
// No conflict case
System.out.println("\n=== NO CONFLICT CASE ===");
PeacefulWriter peaceful = new PeacefulWriter();
peaceful.setContent("Peaceful content");
peaceful.write(); // Uses Writer's default method
peaceful.edit();
// Demonstrate polymorphism
System.out.println("\n=== POLYMORPHISM DEMO ===");
Writer writer1 = new SmartWriter();
((SmartWriter) writer1).setContent("Polymorphic content");
writer1.write(); // Calls overridden method
Writer writer2 = new PeacefulWriter();
((PeacefulWriter) writer2).setContent("Default method content");
writer2.write(); // Calls default method from Writer interface
}
}
Output:
=== DEFAULT METHOD CONFLICTS AND SOLUTIONS === === SOLUTION 1: OVERRIDE === Smart writing: Hello World Publishing to blog platform === SOLUTION 2: EXPLICIT SELECTION === Writing news report: Breaking News! Writing blog post: Breaking News! As Blogger: Writing blog post: Breaking News! As Reporter: Writing news report: Breaking News! === NO CONFLICT CASE === Writing generic content Editing content: Peaceful content === POLYMORPHISM DEMO === Smart writing: Polymorphic content Writing generic content
Example 4: Complex Multiple Inheritance Scenario
import java.util.ArrayList;
import java.util.List;
// Payment-related interfaces
interface Payable {
void processPayment(double amount);
String getPaymentMethod();
}
interface Refundable {
void processRefund(double amount);
boolean isRefundAllowed();
}
interface Taxable {
double calculateTax(double amount);
void setTaxRate(double rate);
}
// Shipping-related interfaces
interface Shippable {
void shipProduct(String address);
double calculateShippingCost(String address);
String getTrackingNumber();
}
interface Trackable {
void updateLocation(String location);
String getCurrentLocation();
String getEstimatedDelivery();
}
// Product-related interfaces
interface Product {
String getName();
double getPrice();
int getStockQuantity();
}
interface Discountable {
void applyDiscount(double percentage);
double getDiscountedPrice();
}
// Digital product specific
interface Downloadable {
void download();
String getDownloadLink();
long getFileSize();
}
// Service specific
interface Service {
void provideService();
int getServiceDuration(); // in minutes
boolean isRecurring();
}
// π― CLASS WITH COMPLEX MULTIPLE INHERITANCE
class DigitalProduct implements Product, Payable, Refundable, Taxable, Downloadable {
private String name;
private double price;
private int stock;
private double taxRate;
private String downloadLink;
private long fileSize;
public DigitalProduct(String name, double price, int stock, String downloadLink, long fileSize) {
this.name = name;
this.price = price;
this.stock = stock;
this.downloadLink = downloadLink;
this.fileSize = fileSize;
this.taxRate = 0.10; // 10% default tax
}
// Product interface
@Override public String getName() { return name; }
@Override public double getPrice() { return price; }
@Override public int getStockQuantity() { return stock; }
// Payable interface
@Override
public void processPayment(double amount) {
double total = amount + calculateTax(amount);
System.out.println("Processing digital payment: $" + total);
System.out.println("Payment method: Credit Card");
}
@Override
public String getPaymentMethod() {
return "Online Payment";
}
// Refundable interface
@Override
public void processRefund(double amount) {
System.out.println("Processing digital refund: $" + amount);
}
@Override
public boolean isRefundAllowed() {
return true; // Digital products usually allow refunds
}
// Taxable interface
@Override
public double calculateTax(double amount) {
return amount * taxRate;
}
@Override
public void setTaxRate(double rate) {
this.taxRate = rate;
}
// Downloadable interface
@Override
public void download() {
System.out.println("Downloading: " + name);
System.out.println("Link: " + downloadLink);
System.out.println("File size: " + fileSize + " bytes");
stock--; // Reduce stock when downloaded
}
@Override
public String getDownloadLink() {
return downloadLink;
}
@Override
public long getFileSize() {
return fileSize;
}
// DigitalProduct specific method
public void displayDigitalInfo() {
System.out.println("=== DIGITAL PRODUCT INFO ===");
System.out.println("Name: " + name);
System.out.println("Price: $" + price);
System.out.println("Tax: " + (taxRate * 100) + "%");
System.out.println("Stock: " + stock);
System.out.println("File Size: " + fileSize + " bytes");
System.out.println("Refund Allowed: " + isRefundAllowed());
}
}
class PhysicalProduct implements Product, Payable, Refundable, Taxable, Shippable, Trackable, Discountable {
private String name;
private double price;
private int stock;
private double taxRate;
private double discountRate;
private String currentLocation;
private String trackingNumber;
public PhysicalProduct(String name, double price, int stock) {
this.name = name;
this.price = price;
this.stock = stock;
this.taxRate = 0.08; // 8% default tax
this.discountRate = 0.0;
this.currentLocation = "Warehouse";
this.trackingNumber = "TRK" + System.currentTimeMillis();
}
// Product interface
@Override public String getName() { return name; }
@Override public double getPrice() { return price; }
@Override public int getStockQuantity() { return stock; }
// Payable interface
@Override
public void processPayment(double amount) {
double total = amount + calculateTax(amount);
System.out.println("Processing physical product payment: $" + total);
}
@Override
public String getPaymentMethod() {
return "Credit Card/PayPal";
}
// Refundable interface
@Override
public void processRefund(double amount) {
System.out.println("Processing physical product refund: $" + amount);
stock++; // Increase stock when refunded
}
@Override
public boolean isRefundAllowed() {
return true; // Physical products usually allow refunds
}
// Taxable interface
@Override
public double calculateTax(double amount) {
return amount * taxRate;
}
@Override
public void setTaxRate(double rate) {
this.taxRate = rate;
}
// Shippable interface
@Override
public void shipProduct(String address) {
System.out.println("Shipping " + name + " to: " + address);
currentLocation = "In Transit";
stock--; // Reduce stock when shipped
}
@Override
public double calculateShippingCost(String address) {
// Simple calculation based on address length (for demo)
return address.length() * 0.5;
}
@Override
public String getTrackingNumber() {
return trackingNumber;
}
// Trackable interface
@Override
public void updateLocation(String location) {
this.currentLocation = location;
System.out.println(name + " location updated to: " + location);
}
@Override
public String getCurrentLocation() {
return currentLocation;
}
@Override
public String getEstimatedDelivery() {
return "2-3 business days";
}
// Discountable interface
@Override
public void applyDiscount(double percentage) {
this.discountRate = percentage / 100.0;
System.out.println("Applied " + percentage + "% discount");
}
@Override
public double getDiscountedPrice() {
return price * (1 - discountRate);
}
// PhysicalProduct specific method
public void displayPhysicalInfo() {
System.out.println("=== PHYSICAL PRODUCT INFO ===");
System.out.println("Name: " + name);
System.out.println("Original Price: $" + price);
System.out.println("Discounted Price: $" + getDiscountedPrice());
System.out.println("Tax: " + (taxRate * 100) + "%");
System.out.println("Stock: " + stock);
System.out.println("Location: " + currentLocation);
System.out.println("Tracking: " + trackingNumber);
System.out.println("Delivery: " + getEstimatedDelivery());
}
}
public class ComplexMultipleInheritance {
public static void main(String[] args) {
System.out.println("=== COMPLEX MULTIPLE INHERITANCE DEMO ===");
// Create products
DigitalProduct ebook = new DigitalProduct("Java Programming Guide", 29.99, 1000,
"https://example.com/download/java-guide", 2048576);
PhysicalProduct laptop = new PhysicalProduct("Gaming Laptop", 1299.99, 50);
laptop.applyDiscount(10); // 10% discount
System.out.println();
// Demonstrate digital product capabilities
System.out.println("=== DIGITAL PRODUCT OPERATIONS ===");
ebook.displayDigitalInfo();
ebook.processPayment(ebook.getPrice());
ebook.download();
System.out.println();
// Demonstrate physical product capabilities
System.out.println("=== PHYSICAL PRODUCT OPERATIONS ===");
laptop.displayPhysicalInfo();
laptop.processPayment(laptop.getDiscountedPrice());
laptop.shipProduct("123 Main St, New York, NY");
laptop.updateLocation("Distribution Center");
System.out.println("Current location: " + laptop.getCurrentLocation());
System.out.println("Shipping cost: $" + laptop.calculateShippingCost("123 Main St"));
System.out.println();
// Polymorphic processing
System.out.println("=== POLYMORPHIC PROCESSING ===");
Product[] products = {ebook, laptop};
Payable[] payables = {ebook, laptop};
Refundable[] refundables = {ebook, laptop};
System.out.println("Products:");
for (Product product : products) {
System.out.println("- " + product.getName() + ": $" + product.getPrice());
}
System.out.println("\nPayment processing:");
for (Payable payable : payables) {
payable.processPayment(payable instanceof DigitalProduct ?
((DigitalProduct) payable).getPrice() :
((PhysicalProduct) payable).getDiscountedPrice());
}
System.out.println("\nRefund capabilities:");
for (Refundable refundable : refundables) {
System.out.println("Refund allowed: " + refundable.isRefundAllowed());
}
// Interface-specific arrays
System.out.println("\n=== INTERFACE-SPECIFIC ARRAYS ===");
Taxable[] taxables = {ebook, laptop};
for (Taxable taxable : taxables) {
double tax = taxable.calculateTax(100);
System.out.println("Tax on $100: $" + tax);
}
// Only physical products are shippable and trackable
System.out.println("\n=== SHIPPING AND TRACKING (Physical Only) ===");
Shippable[] shippables = {laptop}; // ebook doesn't implement Shippable
Trackable[] trackables = {laptop}; // ebook doesn't implement Trackable
for (Shippable shippable : shippables) {
System.out.println("Tracking number: " + shippable.getTrackingNumber());
}
for (Trackable trackable : trackables) {
System.out.println("Estimated delivery: " + trackable.getEstimatedDelivery());
}
}
}
Output:
=== COMPLEX MULTIPLE INHERITANCE DEMO === === DIGITAL PRODUCT OPERATIONS === === DIGITAL PRODUCT INFO === Name: Java Programming Guide Price: $29.99 Tax: 10.0% Stock: 1000 File Size: 2048576 bytes Refund Allowed: true Processing digital payment: $32.989 Payment method: Credit Card Downloading: Java Programming Guide Link: https://example.com/download/java-guide File size: 2048576 bytes === PHYSICAL PRODUCT OPERATIONS === === PHYSICAL PRODUCT INFO === Name: Gaming Laptop Original Price: $1299.99 Discounted Price: $1169.991 Tax: 8.0% Stock: 50 Location: Warehouse Tracking: TRK1705327845123 Delivery: 2-3 business days Processing physical product payment: $1263.59028 Shipping Gaming Laptop to: 123 Main St, New York, NY Gaming Laptop location updated to: Distribution Center Current location: Distribution Center Shipping cost: $17.0 === POLYMORPHIC PROCESSING === Products: - Java Programming Guide: $29.99 - Gaming Laptop: $1299.99 Payment processing: Processing digital payment: $32.989 Payment method: Credit Card Processing physical product payment: $1263.59028 Refund capabilities: Refund allowed: true Refund allowed: true === INTERFACE-SPECIFIC ARRAYS === Tax on $100: $10.0 Tax on $100: $8.0 === SHIPPING AND TRACKING (Physical Only) === Tracking number: TRK1705327845123 Estimated delivery: 2-3 business days
Multiple Inheritance Rules and Resolution
β Rules for Multiple Interface Inheritance:
- A class can implement multiple interfaces
- An interface can extend multiple interfaces
- Default method conflicts must be resolved by the implementing class
- Abstract method conflicts are fine - class implements them once
- Constants with same name must be qualified with interface name
β Conflict Resolution:
interface A { default void foo() { System.out.println("A"); } }
interface B { default void foo() { System.out.println("B"); } }
class C implements A, B {
// β Must resolve conflict
@Override
public void foo() {
A.super.foo(); // Explicitly choose A's implementation
// OR
B.super.foo(); // Explicitly choose B's implementation
// OR
System.out.println("C"); // Provide new implementation
}
}
Benefits of Multiple Inheritance via Interfaces
β Advantages:
- Rich behaviors - classes can have multiple capabilities
- Flexible design - mix and match interfaces as needed
- No diamond problem - interfaces don't have state
- Loose coupling - depend on abstractions, not implementations
- Testability - easy to mock interfaces
β Design Patterns Enabled:
- Adapter Pattern - implement multiple interfaces to adapt classes
- Decorator Pattern - add behaviors via interfaces
- Strategy Pattern - different implementations of same interface
- Observer Pattern - multiple listener interfaces
Best Practices
β Interface Design:
- Keep interfaces focused (Single Responsibility Principle)
- Use descriptive names for interfaces
- Group related methods in the same interface
- Consider interface segregation - many small interfaces vs one large one
β Implementation:
- Resolve default method conflicts explicitly
- Document which interfaces a class implements and why
- Use @Override annotation for clarity
- Test each interface contract separately
// β
GOOD: Segregated interfaces
interface Readable { void read(); }
interface Writable { void write(); }
interface Deletable { void delete(); }
// Class can choose which capabilities it needs
class File implements Readable, Writable, Deletable {
// Implement methods...
}
Common Pitfalls
// β BAD: Too many unrelated interfaces
class GodObject implements A, B, C, D, E, F, G {
// Becomes hard to maintain and understand
}
// β
BETTER: Logical grouping
interface Vehicle { /* vehicle methods */ }
interface Electric { /* electric specific */ }
interface Autonomous { /* self-driving */ }
class Tesla implements Vehicle, Electric, Autonomous {
// Clear, focused responsibilities
}
Conclusion
Multiple Inheritance via Interfaces is Java's superpower for building flexible, maintainable systems:
- β Combine multiple behaviors in a single class
- β Avoid the diamond problem of traditional multiple inheritance
- β Enable rich polymorphism - one object, many types
- β Support design principles like Interface Segregation
- β Provide compile-time safety - all methods must be implemented
Key Takeaways:
- Java allows multiple interface inheritance but not multiple class inheritance
- Default method conflicts must be resolved by implementing classes
- Interfaces define contracts - classes provide implementations
- Design with interfaces for maximum flexibility and testability
- Use multiple interfaces to create rich, complex behaviors
Multiple inheritance via interfaces transforms Java from a simple single-inheritance language into a powerful platform for building complex, well-architected systems. It's the foundation upon which enterprise Java frameworks are built!