9 Module 9 — Chapter 13

🔗 Java Interfaces

Contracts, Behaviors, and Flexible Design
Hello, my students!
Today we discover one of Java's most powerful and unique features — the Interface. This is something you will not find in C++ in the same form, and it exists in Java for very important reasons. By the end of today, you will understand why interfaces exist, how to use them, and when they are the right tool — and you will be amazed by their elegance.
✅ Encapsulation
✅ Abstraction
✅ Inheritance
✅ Polymorphism
✅ Abstract Classes
🔗 Interfaces (today)

! Critical Distinction — Class vs. Interface

Before we write a single line of code, we must establish a fundamental difference in philosophy between a class and an interface. This is the most important idea in this entire module.

🏢
CLASS — Identity
"What it IS"
A class defines what an object is.

Animal — it is a living creature
Fruit — it is a type of food
Student — it is a person who studies
Car — it is a vehicle

This is the identity — the is-a relationship.
🔗
INTERFACE — Behavior
"What it CAN DO"
An interface defines what an object can do.

Flyable — it can fly
Edible — it can be eaten
Comparable — it can be compared
Printable — it can be printed

This is the behavior — the can-do relationship.
🔑 The Golden Insight

A Bird and a Drone have no common identity — Bird is an Animal, Drone is Equipment.
They are not related by class hierarchy. But they share a behavior: both can fly.

An interface captures this shared behavior across completely unrelated classes — this is something you cannot achieve with inheritance alone.

🐦 Bird (Animal)
+
Drone (Equipment)
✈️ Flyable «interface»

1 Why Java Has No Multiple Inheritance — The Diamond Problem

To understand why interfaces were introduced in Java, we must first understand a deliberate design decision: Java does NOT support multiple inheritance of classes. This is not a limitation — it is a careful, intentional choice.

🚫 Java's Rule — Single Inheritance Only

In Java, a class can extend only ONE class.
Writing class D extends B, C is a compile error in Java.

The reason: a famous problem known as the Diamond Problem.

The Diamond Problem 💎 Understanding the Ambiguity

Imagine we have four classes: A, B, C, and D. Class A has a method greet(). Both B and C inherit from A and override greet() with different implementations. Now, if Java allowed multiple inheritance and D extends both B and C:

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#f8fafc', 'primaryTextColor': '#1f2937', 'primaryBorderColor': '#94a3b8', 'lineColor': '#374151'}}}%% classDiagram direction BT class A { +greet() Hello from A } class B { +greet() Hello from B } class C { +greet() Hello from C } class D { +greet() B or C ??? Ambiguous! } B --|> A : extends C --|> A : extends D --|> B : extends D --|> C : extends FORBIDDEN style A fill:#fef9c3,stroke:#d97706,color:#92400e style B fill:#dbeafe,stroke:#2563eb,color:#1e40af style C fill:#dbeafe,stroke:#2563eb,color:#1e40af style D fill:#fce7f3,stroke:#db2777,color:#9d174d
d.greet()  ←  Which version does D inherit?
B overrides greet()  |  C overrides greet()  |  No clear answer!
🚨 The Ambiguity — Why This Is a Problem

When class D calls d.greet(), the compiler faces an impossible question:

  • Should it call B's version: "Hello from B"?
  • Or should it call C's version: "Hello from C"?
  • Or the original A's version?

There is no clear, unambiguous answer. This is the Diamond Problem — named because the inheritance diagram forms a diamond shape. Java avoids this entirely by forbidding multiple class inheritance.

Java's Design 🆕 Hierarchy Only — Structured and Predictable

Java's solution: allow only single inheritance in a hierarchy. This makes the language structured, predictable, and free of ambiguity.

❌ NOT Allowed in Java
class D extends B, C ← ERROR
class D extends B extends C ← ERROR
✅ Allowed — Hierarchy Chain
class Student extends Person
class GradStudent extends Student
💡 Java is Structured and Predictable

Java's inheritance is like a family tree: one parent, one grandparent, one chain. This is clear and unambiguous.

Example: GradStudent extends Student extends Person. This is clean, readable, and predictable — exactly how Java was designed.

But this raises a question: how do we handle objects that share behavior but have no common ancestor? That is exactly where interfaces come in.

2 The Problem That Hierarchy Cannot Solve

Now let us work through a real design problem that shows exactly why interfaces were introduced. Follow every step carefully — the solution will surprise you.

Our World 🆕 Four Objects

🍎 Apple
🍊 Orange
🐔 Chicken
🐯 Tiger

Step 1 📋 First Design — Using Hierarchy

As a good OOP student, you immediately think in hierarchy:

  • Apple and Orange are both Fruit → create a Fruit parent class
  • Chicken and Tiger are both Animal → create an Animal parent class
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#f8fafc', 'primaryTextColor': '#1f2937', 'primaryBorderColor': '#94a3b8', 'lineColor': '#374151'}}}%% classDiagram direction TB class Animal { -String name +Animal(name) +getName() String +toString() String } class Fruit { -String name +Fruit(name) +getName() String +toString() String } class Tiger { +Tiger() +roar() void } class Chicken { +Chicken() +cluck() void } class Apple { +Apple() +getColor() String } class Orange { +Orange() +getJuice() double } Animal <|-- Tiger : extends Animal <|-- Chicken : extends Fruit <|-- Apple : extends Fruit <|-- Orange : extends style Animal fill:#dbeafe,stroke:#2563eb,color:#1e40af style Fruit fill:#dcfce7,stroke:#16a34a,color:#14532d style Tiger fill:#fef9c3,stroke:#d97706,color:#92400e style Chicken fill:#fef9c3,stroke:#d97706,color:#92400e style Apple fill:#bbf7d0,stroke:#15803d,color:#14532d style Orange fill:#bbf7d0,stroke:#15803d,color:#14532d
✅ Good Design so Far!

We can use Animal polymorphically for Tiger and Chicken, and Fruit polymorphically for Apple and Orange. Hierarchy works perfectly here — no code duplication.

Step 2 🤔 A New Requirement Appears

🏫 In the classroom...

👨‍🏫 The Professor asks:
My students — look at these four objects: Apple, Orange, Chicken, Tiger. Is there any relationship among some of them that we have not captured yet?
👤 Student raises hand:
Doctor! Yes! We can eat the Apple, the Orange, and the Chicken. They are all edible!
👨‍🏫 The Professor:
Excellent! Apple, Orange, and Chicken are all edible. But Tiger is not!

Now I want to store Apple, Orange, and Chicken in a single array — but only them, not Tiger. What type should this array be?
👤 Another student:
Doctor, I can use an Object[] array! Everything in Java is an Object, so it can hold anything.
👨‍🏫 The Professor:
Yes, absolutely correct, my student! Object[] can hold anything. But there is a problem — it can also hold a Tiger! We want the compiler to guarantee that only edible objects go into our array.

Object[] is too broad. We need a precise type. How do we design this?

Step 3 🤔 Students Try a Design — What Do You Think?

The professor asks the students to try solving this themselves before giving the answer. One idea the students propose: "Let us make Edible a class, and let Apple, Orange, and Chicken inherit from it."

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#f8fafc', 'primaryTextColor': '#1f2937', 'primaryBorderColor': '#94a3b8', 'lineColor': '#374151'}}}%% classDiagram direction TB class Edible { +howToEat() String } class Fruit { -String name +getName() String } class Apple { +Apple() +howToEat() String } class Orange { +Orange() +howToEat() String } class Chicken { +Chicken() +howToEat() String } class Animal { -String name +getName() String } class Tiger { +Tiger() +roar() void } Edible <|-- Fruit : extends Edible <|-- Chicken : extends Fruit <|-- Apple : extends Fruit <|-- Orange : extends Animal <|-- Tiger : extends style Edible fill:#f5f3ff,stroke:#7c3aed,color:#4c1d95 style Fruit fill:#ccfbf1,stroke:#0d9488,color:#134e4a style Apple fill:#bbf7d0,stroke:#15803d,color:#14532d style Orange fill:#bbf7d0,stroke:#15803d,color:#14532d style Chicken fill:#fef9c3,stroke:#d97706,color:#92400e style Animal fill:#dbeafe,stroke:#2563eb,color:#1e40af style Tiger fill:#fee2e2,stroke:#dc2626,color:#991b1b

🏫 In the classroom — students evaluate the design...

👨‍🏫 The Professor:
My students — look at this design. We made Edible a class, and Chicken now extends Edible instead of Animal. Apple and Orange inherit through Fruit. Tiger stays in the Animal hierarchy separately.

Now we can create an Edible[] array holding Apple, Orange, and Chicken — and Tiger cannot go in! Is this a good design?
👤 A student raises his hand:
Doctor — I see a big problem here!

If Chicken now extends Edible, it no longer extends Animal. But Chicken and Tiger are both animals — they share many common features: breathe(), move(), makeSound(), eat(), sleep(), and maybe hundreds more.

If Chicken does not extend Animal, we must write all of those features twice — once in Chicken, once in Tiger. This is code duplication! This violates the whole reason we use inheritance!
👨‍🏫 The Professor:
Excellent! You are absolutely correct, my student.

This design forces us to choose: either Chicken inherits its animal behaviors, or it is edible — but not both, because Java allows only one parent class.

No matter how we rearrange the hierarchy, we cannot solve this cleanly. This is exactly why we need something completely different — something that is not a class at all.
🚨 The Core Problem with This Design

If Tiger and Chicken share 100 common features as animals, and Chicken is forced out of the Animal hierarchy to become edible — we must duplicate all 100 features in both classes. The bigger the shared feature set, the worse this design becomes. Hierarchy cannot solve this problem.

Step 4 💥 Why Every Hierarchy Attempt Fails

Attempt 1: Make both Animal and Fruit extend a common Edible class

What if we place howToEat() in a top-level Edible class, then make Animal and Fruit both extend it? The full hierarchy looks like this:

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#f8fafc', 'primaryTextColor': '#1f2937', 'primaryBorderColor': '#94a3b8', 'lineColor': '#374151'}}}%% classDiagram direction TB class Edible { +howToEat() String } class Animal { +howToEat() String +breathe() +move() +makeSound() } class Fruit { +howToEat() String +grow() } class Tiger { +makeSound() } class Chicken { +makeSound() } class Apple class Orange Edible <|-- Animal Edible <|-- Fruit Animal <|-- Tiger Animal <|-- Chicken Fruit <|-- Apple Fruit <|-- Orange style Edible fill:#f5f3ff,stroke:#7c3aed,color:#4c1d95 style Animal fill:#fee2e2,stroke:#dc2626,color:#7f1d1d style Fruit fill:#d1fae5,stroke:#059669,color:#064e3b style Tiger fill:#fef3c7,stroke:#d97706,color:#78350f style Chicken fill:#dbeafe,stroke:#2563eb,color:#1e40af style Apple fill:#d1fae5,stroke:#059669,color:#064e3b style Orange fill:#fff7ed,stroke:#ea580c,color:#7c2d12
👨‍🏫
Now we have a clean hierarchy. Edible[] can hold anything that is edible. Let's fill an array with what we want to eat…
👁︎ Show Code — Edible[] array
👨‍🏫
The array accepts Chicken ✅, Apple ✅, Orange ✅ — good. But look at the last line… it also accepts Tiger ❌. Because Tiger inherits from Animal, and Animal inherits from Edible, Java sees Tiger as Edible. The type system cannot stop it.
🙋
Oh no — so anyone can accidentally add a Tiger to the "food" array? There is no compiler error?
👨‍🏫
Exactly. No compiler error, no runtime error at the moment of insertion — the bug is silent and dangerous. Making Animal extend Edible poisons the entire Animal hierarchy.

❌ Tiger becomes Edible — the entire Animal branch is contaminated.

💡 The Conclusion That Motivates Interfaces

My students — if you try every possible hierarchy design, you will not find a clean solution.

This problem cannot be solved by inheritance hierarchy alone in a language that supports only single class inheritance.

We need a new concept: a way for objects to share a behavior even when they have no common class ancestor.

That concept is the Interface.

3 What is an Interface? — Definition and Rules

🔘 Most Important — Read This First

An interface is NOT a class. It is a class-like construct — it has a similar look but a completely different purpose.

An interface does not define objects. It defines a set of behaviors (method headers) that any willing class can promise to implement.

When a class implements an interface, it makes a promise to the compiler: "I guarantee that I have all these behaviors."

Rules 📋 The Five Rules of an Interface

1 All methods are implicitly public abstract

Every method inside an interface is automatically public and abstract — even if you do not write these keywords explicitly. There is no method body — only the method signature (header).

📄 Interface method — no body
public interface Edible { // These two lines mean exactly the same thing: public abstract String howToEat(); // explicit String howToEat(); // shorter — same meaning! }
2 All variables are implicitly public static final (constants)

Any variable declared in an interface is automatically a constant. You cannot have regular instance variables — only final, shared constants.

📄 Interface constants
public interface NutritionInfo { // Implicitly: public static final int MAX_CALORIES = 2000 int MAX_CALORIES = 2000; // ← constant, shared by all implementors int PORTIONS = 5; String getIngredients(); // abstract method }
3 A class uses implements — and must override ALL abstract methods

To adopt an interface, a class uses the keyword implements (not extends). It then must provide a body for every abstract method in the interface. If even one method is missing, it is a compile error.

📄 implements keyword
// Apple is a Fruit (identity) AND it is Edible (behavior) public class Apple extends Fruit implements Edible { @Override public String howToEat() { // MUST be implemented return "Peel and eat the apple fresh."; } }
4 A class can implement MULTIPLE interfaces — Java's flexibility!

This is Java's powerful answer to multiple inheritance. A class can only extend one parent class, but it can implement as many interfaces as needed. There is no diamond problem because interfaces have no state and no implementation.

📄 Multiple interfaces — no diamond problem
// ✅ A class can implement multiple interfaces — no conflict! public class Chicken extends Animal implements Edible, Flyable { @Override public String howToEat() { /* Chicken provides THIS body */ } @Override public void fly() { /* Chicken provides THIS body */ } // No ambiguity — Chicken always defines the behavior itself! }
5 An interface is a valid data type — enables polymorphism!

An interface can be used as a polymorphic variable type. An array of type Edible[] can hold any object whose class implements Edible — and only those objects.

📄 Interface as data type
Edible[] list = new Edible[3]; list[0] = new Apple(); // ✅ Apple implements Edible list[1] = new Orange(); // ✅ Orange implements Edible list[2] = new Chicken(); // ✅ Chicken implements Edible // list[3] = new Tiger(); ← ❌ Compile error! Tiger is NOT Edible // The compiler protects you — Tiger cannot sneak in!

4 Solving the Edible Problem — Full Implementation

Now let us build the complete solution. Here is the final design that solves the problem hierarchy could not:

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#f8fafc', 'primaryTextColor': '#1f2937', 'primaryBorderColor': '#94a3b8', 'lineColor': '#374151'}}}%% classDiagram direction TB class Edible { <<interface>> +howToEat() String } class Animal { <<abstract>> -String name +Animal(name) +getName() String +toString() String } class Fruit { <<abstract>> -String name +Fruit(name) +getName() String +toString() String } class Tiger { +Tiger() +roar() void } class Chicken { +Chicken() +howToEat() String } class Apple { +Apple() +howToEat() String } class Orange { +Orange() +howToEat() String } Animal <|-- Tiger : extends Animal <|-- Chicken : extends Fruit <|-- Apple : extends Fruit <|-- Orange : extends Edible <|.. Fruit : implements Edible <|.. Chicken : implements style Edible fill:#f5f3ff,stroke:#7c3aed,color:#4c1d95 style Animal fill:#dbeafe,stroke:#2563eb,color:#1e40af style Fruit fill:#ccfbf1,stroke:#0d9488,color:#134e4a style Tiger fill:#fee2e2,stroke:#dc2626,color:#991b1b style Chicken fill:#ccfbf1,stroke:#0d9488,color:#134e4a style Apple fill:#dcfce7,stroke:#16a34a,color:#14532d style Orange fill:#fff7ed,stroke:#ea580c,color:#7c2d12
📌 Reading the UML Diagram
  • Solid arrow with hollow triangle (▶) = extends (class inheritance)
  • Dashed arrow with hollow triangle (➪▶) = implements (interface)
  • <<interface>> = this is an interface, not a class
  • Tiger extends Animal but does NOT implement Edible — intentional!
  • Chicken both extends Animal AND implements Edible — simultaneously!

Step 1 The Edible Interface

👁︎ Hide Code — Edible.java
// Edible.java public interface Edible { /** * Describes how this object is eaten. * Implicitly: public abstract String howToEat() */ String howToEat(); }

Step 2 The Base Classes

👁︎ Hide Code — Animal.java & Fruit.java
// Animal.java public class Animal { private String name; public Animal(String name) { this.name = name; } public String getName() { return name; } @Override public String toString() { return "Animal[" + name + "]"; } } // Fruit.java public class Fruit { private String name; public Fruit(String name) { this.name = name; } public String getName() { return name; } @Override public String toString() { return "Fruit[" + name + "]"; } }

Step 3 The Concrete Classes

👁︎ Hide Code — Apple.java & Orange.java
// Apple.java — identity: Fruit | behavior: Edible public class Apple extends Fruit implements Edible { public Apple() { super("Apple"); } @Override public String howToEat() { return "Peel and eat the apple fresh."; } } // Orange.java — identity: Fruit | behavior: Edible public class Orange extends Fruit implements Edible { public Orange() { super("Orange"); } @Override public String howToEat() { return "Peel and eat the orange in slices."; } }
👁︎ Hide Code — Chicken.java & Tiger.java
// Chicken.java — identity: Animal | behavior: Edible public class Chicken extends Animal implements Edible { public Chicken() { super("Chicken"); } @Override public String howToEat() { return "Grill or fry the chicken and serve hot."; } } // Tiger.java — identity: Animal | does NOT implement Edible public class Tiger extends Animal { public Tiger() { super("Tiger"); } public void roar() { System.out.println("ROARRR!"); } // Tiger intentionally does NOT implement Edible! }

Step 4 The Polymorphic Test Program

👁︎ Hide Code — TestEdible.java
// TestEdible.java public class TestEdible { public static void main(String[] args) { // ✅ An Edible array — compiler only allows Edible objects! Edible[] edibles = { new Apple(), // ✅ Apple implements Edible new Orange(), // ✅ Orange implements Edible new Chicken() // ✅ Chicken implements Edible }; System.out.println("=== How to eat each item ==="); for (Edible item : edibles) { System.out.println(item.howToEat()); // polymorphic call! } // ❌ This line would cause a compile error: // edibles[3] = new Tiger(); Tiger is NOT Edible! } }
Output — TestEdible.java
=== How to eat each item === Peel and eat the apple fresh. Peel and eat the orange in slices. Grill or fry the chicken and serve hot.
🎉 Problem Solved — Notice What We Achieved
  • Apple, Orange, and Chicken share the Edible relationship ✅
  • Tiger is correctly excluded — the compiler enforces this automatically ✅
  • We use a single Edible[] array to treat them polymorphically ✅
  • Chicken still inherits from Animal — we lost nothing from the hierarchy ✅
  • Apple and Orange still inherit from Fruit — no duplication ✅

5 Interface as a Contract — Parallel Development

The second great purpose of interfaces is to serve as a contract — a formal, compiler-enforced agreement between developers that certain behaviors will exist. This enables something very powerful in software engineering.

The Story 📚 Ali and Ahmed — Working in Parallel

🏫 A real software project scenario...

👨‍🏫 The Professor sets the scene:
We want to build an arithmetic quiz program for children. The program generates math questions (addition, multiplication) and checks if the child's answer is correct.

Ali will build the logic classes: Addition, Multiplication.
Ahmed will build the main quiz program that uses these classes.

Problem: Ali says it will take him one week to finish his work. Should Ahmed wait one full week, doing nothing?
👤 Students:
No Doctor! That is a waste of time. But how can Ahmed write a program that depends on code that does not exist yet?
👨‍🏫 The Professor:
Excellent question! The answer is the Interface as Contract.

Before Ali starts coding, he and Ahmed sit together and define an interface that specifies exactly what Ali's classes must provide. This interface is their contract — their promise to each other.

Ahmed writes his program using the interface as the data type. Ali builds his classes to fulfill the interface. They work simultaneously — and the moment Ali finishes, Ahmed's program works immediately without any changes!
👨‍💻
Ali — Implementer
Builds Addition and
Multiplication classes.

Must implement every
method in the interface.
🔗
INTERFACE
CONTRACT
agreed by both
before coding starts
👨‍💻
Ahmed — Tester
Builds the quiz program.
Uses the interface as
the variable type.

Works independently of Ali.
⚡ Both developers work simultaneously! When Ali finishes, Ahmed's code works immediately — zero changes needed.

Step 1 The Contract Interface

👁︎ Hide Code — ArithmeticOperation.java
// ArithmeticOperation.java — the contract agreed by Ali and Ahmed public interface ArithmeticOperation { /** Generates two random numbers for the question */ void generateNumbers(); /** Displays the math question to the user */ void displayQuestion(); /** Returns true if the given answer is correct */ boolean checkAnswer(int answer); /** Returns the name of this operation (e.g., "Addition") */ String getOperationName(); }

Step 2 Ali's Implementation

👁︎ Hide Code — Addition.java (Ali builds this)
// Addition.java — Ali's work (implements the contract) public class Addition implements ArithmeticOperation { private int num1, num2; @Override public void generateNumbers() { num1 = (int)(Math.random() * 10) + 1; num2 = (int)(Math.random() * 10) + 1; } @Override public void displayQuestion() { System.out.println("What is " + num1 + " + " + num2 + " = ?"); } @Override public boolean checkAnswer(int answer) { return answer == (num1 + num2); } @Override public String getOperationName() { return "Addition"; } }
👁︎ Hide Code — Multiplication.java (Ali builds this)
// Multiplication.java — Ali's work (implements the contract) public class Multiplication implements ArithmeticOperation { private int num1, num2; @Override public void generateNumbers() { num1 = (int)(Math.random() * 10) + 1; num2 = (int)(Math.random() * 10) + 1; } @Override public void displayQuestion() { System.out.println("What is " + num1 + " x " + num2 + " = ?"); } @Override public boolean checkAnswer(int answer) { return answer == (num1 * num2); } @Override public String getOperationName() { return "Multiplication"; } }

Step 3 Ahmed's Quiz Program

👁︎ Hide Code — QuizApp.java (Ahmed builds this in parallel)
// QuizApp.java — Ahmed's work (uses the interface as the type) import java.util.Scanner; public class QuizApp { public static void main(String[] args) { Scanner sc = new Scanner(System.in); // Ahmed uses ArithmeticOperation (interface) as the type // — NOT Addition or Multiplication directly! ArithmeticOperation[] operations = { new Addition(), new Multiplication() }; int score = 0; for (ArithmeticOperation op : operations) { System.out.println("\n--- " + op.getOperationName() + " ---"); op.generateNumbers(); op.displayQuestion(); System.out.print("Your answer: "); int answer = sc.nextInt(); if (op.checkAnswer(answer)) { System.out.println("Correct! Well done!"); score++; } else { System.out.println("Wrong. Try again next time."); } } System.out.println("\nFinal score: " + score + "/" + operations.length); sc.close(); } }
Sample Run — QuizApp.java
--- Addition --- What is 7 + 4 = ? Your answer: 11 Correct! Well done! --- Multiplication --- What is 3 x 6 = ? Your answer: 18 Correct! Well done! Final score: 2/2
🎉 The Power of the Contract
  • Ahmed used ArithmeticOperation as the type — never the concrete class
  • Ali can refactor or improve his implementation — Ahmed's code still works unchanged
  • Adding Subtraction or Division requires only: create new class, implement interface — Ahmed's loop handles it automatically
  • The interface guarantees: "anything here will have exactly these four methods"
🔑 Third Use: Sharing Your Algorithm with Others

Suppose you have a powerful algorithm (e.g., a sorting algorithm). You want others to use it, but you need to guarantee that the objects they pass are comparable to each other.

You publish an interface: Comparable. You tell them: "If you want to use my algorithm, implement this interface."
This guarantees 100% behavioral compatibility. The interface is a handshake between your code and theirs — no surprises, no missing methods, no runtime errors.

6 Multiple Interfaces — Java's Answer to Flexibility

A class in Java can implement more than one interface at the same time. This is Java's safe, clean answer to the need for multiple behaviors — without any diamond problem.

Discussion 💬 What do Chicken and Orange have in common?

👨‍🏫
My students — we already know that Chicken and Orange are both Edible. But think deeper: is there any other relationship between them?
🤜
Hmm… both are food… but also… I think both are good for people with diabetes? Chicken has protein and low carbs, and orange has fiber and low glycemic index.
👨‍🏫
Excellent! That is exactly right. So we can model a new behavior: Diabetic-friendly. Let us create a Diabetic interface.

But notice this: if something is good for diabetics, it must also be edible, right? You cannot eat something that is not food. So Diabetic extends Edible.
🙋
Wait — can an interface extend another interface?
👨‍🏫
Yes! Interface-to-interface uses extends, not implements. Any class that implements Diabetic automatically satisfies Edible too — it must provide both methods.
⚡ Interface can extend Interface

interface Diabetic extends Edible
Any class that implements Diabetic must also implement howToEat() from Edible.
This creates a hierarchy of interfaces.

Design 🍳 Who implements what?

🍎
Apple
extends Fruit
Edible 🍳
🍊
Orange
extends Fruit
Edible 🍳 Diabetic 💊
🐔
Chicken
extends Animal
Edible 🍳 Diabetic 💊
🐯
Tiger
extends Animal
❌ Not Edible, Not Diabetic
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#f8fafc', 'primaryTextColor': '#1f2937', 'primaryBorderColor': '#94a3b8', 'lineColor': '#374151'}}}%% classDiagram direction TB class Edible { <<interface>> +howToEat() String } class Diabetic { <<interface>> +isDiabeticFriendly() boolean } class Animal { <<abstract>> -String name +Animal(name) +getName() String } class Fruit { <<abstract>> -String name +Fruit(name) +getName() String } class Tiger { +Tiger() +roar() void } class Chicken { +Chicken() +howToEat() String +isDiabeticFriendly() boolean } class Apple { +Apple() +howToEat() String } class Orange { +Orange() +howToEat() String +isDiabeticFriendly() boolean } Edible <|-- Diabetic : extends Edible <|.. Fruit : implements Fruit <|-- Apple : extends Fruit <|-- Orange : extends Diabetic <|.. Orange : implements Diabetic <|.. Chicken : implements Animal <|-- Tiger : extends Animal <|-- Chicken : extends style Edible fill:#f5f3ff,stroke:#7c3aed,color:#4c1d95 style Diabetic fill:#d1fae5,stroke:#059669,color:#064e3b style Animal fill:#dbeafe,stroke:#2563eb,color:#1e40af style Fruit fill:#fef3c7,stroke:#d97706,color:#78350f style Tiger fill:#fee2e2,stroke:#dc2626,color:#7f1d1d style Chicken fill:#dbeafe,stroke:#2563eb,color:#1e40af style Apple fill:#fff7ed,stroke:#ea580c,color:#7c2d12 style Orange fill:#fff7ed,stroke:#d97706,color:#78350f
📌 Reading the UML
  • Solid arrow = extends (class or interface inheritance)
  • Dashed arrow = implements (class implements interface)
  • Diabetic extends Edible → any class implementing Diabetic must also provide howToEat()
  • Orange satisfies Edible through two paths: via Fruit and via Diabetic — Java handles this cleanly

Full Code 📄 Implementation

👁︎ Show Code — Edible.java & Diabetic.java
👁︎ Show Code — Animal.java & Fruit.java (abstract)
👁︎ Show Code — Tiger.java, Apple.java, Orange.java, Chicken.java
👁︎ Show Code — TestDiabetic.java
Output — TestDiabetic.java
=== Edible things === Peel and eat the apple fresh. Peel and eat the orange in segments. Grill or bake the chicken and serve hot. === Diabetic-friendly things === Orange → diabetic-friendly: true How to eat: Peel and eat the orange in segments. Chicken → diabetic-friendly: true How to eat: Grill or bake the chicken and serve hot.
💡 What We Learned

Interface extends interfaceDiabetic extends Edible creates a behavior hierarchy.
Orange implements two behaviors at once: Edible (through Fruit) + Diabetic (directly).
Chicken gets Edible for free by implementing Diabetic (since Diabetic extends Edible).
Tiger is untouched — still just an Animal, never sneaks into food arrays.
✅ The Edible[] array now only accepts true food — the type system protects us.

7 Revisiting the Payroll Problem — The Promise We Made in Module 07

📒 Do You Remember?

In Module 07 — Polymorphism, we built a Staff Payroll System. We had a hierarchy: StaffMemberEmployee (Executive, Hourly) and Volunteer.

We placed pay() in StaffMember so the polymorphic loop could call it on every element. But this forced Volunteer to have a pay() method returning 0 — even though a volunteer is not paid at all.

The Doctor said: "This is not good design — but we have no better tool yet. We will fix it in the Interfaces chapter."

That time is now. 🌟

The Problem ⚠︎ Volunteer Forced to Have pay()

🙋
Doctor — in module 07 you said putting pay() in StaffMember was not good design because Volunteer had to return 0 even though volunteers never get paid. Can we now fix that?
👨‍🏫
Yes — exactly. Now that we know interfaces, we can fix it perfectly. The solution: remove pay() from StaffMember, create a Payable interface, and let only Employee implement it. Volunteer will have no pay() method at all — which is the truth!
❌ Module 07 Design — pay() in Superclass
StaffMember { pay() → 0 }
  ↳ Employee { pay() → salary }
    ↳ Executive { pay() → salary+bonus }
    ↳ Hourly { pay() → hrs×rate }
  ↳ Volunteer { pay() → 0 } ← forced!

Volunteer is not payable in real life. This is a design smell.

✅ Module 09 Fix — Payable Interface
StaffMember { name, address, phone }
  ↳ Employee implements Payable
    ↳ Executive (inherits Payable)
    ↳ Hourly (inherits Payable)
  ↳ Volunteer  ← no pay() at all ✓

Only paid staff implement Payable. Volunteer is cleanly excluded.

UML 📌 The Clean Design

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#f8fafc', 'primaryTextColor': '#1f2937', 'primaryBorderColor': '#94a3b8', 'lineColor': '#374151'}}}%% classDiagram direction TB class Payable { <<interface>> +pay() double } class StaffMember { <<abstract>> -String name -String address -String phone +getName() String +toString() String } class Employee { <<abstract>> -String ssn #double payRate +pay() double } class Volunteer { +Volunteer(name,address,phone) +toString() String } class Executive { -double bonus +pay() double } class Hourly { -double hoursWorked +pay() double } StaffMember <|-- Employee : extends StaffMember <|-- Volunteer : extends Employee <|-- Executive : extends Employee <|-- Hourly : extends Payable <|.. Employee : implements style Payable fill:#f5f3ff,stroke:#7c3aed,color:#4c1d95 style StaffMember fill:#dbeafe,stroke:#2563eb,color:#1e40af style Employee fill:#ccfbf1,stroke:#0d9488,color:#134e4a style Volunteer fill:#fef3c7,stroke:#d97706,color:#78350f style Executive fill:#ccfbf1,stroke:#0d9488,color:#134e4a style Hourly fill:#ccfbf1,stroke:#0d9488,color:#134e4a
📌 Key Points in this UML
  • Payable is an interface — only Employee implements it
  • Executive and Hourly inherit Payable from Employee — no extra arrow needed
  • Volunteer extends StaffMember only — no connection to Payable whatsoever
  • The payroll loop uses Payable[] — Volunteer can never sneak in

Full Code 📄 The Fixed Design

👁︎ Show Code — Payable.java & StaffMember.java
👁︎ Show Code — Employee.java, Volunteer.java, Executive.java, Hourly.java
👁︎ Show Code — Payroll.java (using Payable[])
Output — Payroll.java
=== Monthly Payroll === Executive[Ali] SAR 10000.00 Hourly[Ahmed] SAR 4000.00 Employee[Sara] SAR 5000.00
🌟 The Promise is Fulfilled

In Module 07 we said: "Volunteer having pay() is not good design — but we have no better tool yet."

Now we do. The Payable interface lets us say exactly which classes are payable — without touching the rest of the hierarchy.

Volunteer has no pay() method — conceptually correct.
Payable[] array only accepts paid staff — the compiler protects us.
✅ The same pattern solved the Tiger/Edible problem — and now the Volunteer/Payable problem.

This is the power of interfaces.

8 Common Mistakes — Avoid These!

Mistake 1: Trying to instantiate an interface

An interface is not a class — you cannot create an object directly from it.

📄 Example
// ❌ WRONG — compile error Edible e = new Edible(); // Error: Edible is abstract; cannot be instantiated // ✅ CORRECT — use a class that implements Edible Edible e = new Apple(); // Apple implements Edible ✓ Edible e = new Chicken(); // Chicken implements Edible ✓
Mistake 2: Forgetting to implement all abstract methods

If a class implements an interface, it must override every single abstract method. Missing even one is a compile error.

📄 Example
public interface ArithmeticOperation { void generateNumbers(); // method 1 void displayQuestion(); // method 2 boolean checkAnswer(int a); // method 3 String getOperationName(); // method 4 } // ❌ WRONG — implements only 2 of 4 methods public class BadClass implements ArithmeticOperation { public void generateNumbers() { /* ... */ } public boolean checkAnswer(int a) { return false; } // COMPILE ERROR: must implement displayQuestion() and getOperationName() }
💡 Solution
Either implement all methods, or declare the class as abstract — then a concrete subclass must complete them.
Mistake 3: Using "extends" instead of "implements"
📄 Example
// ❌ WRONG — a class cannot "extend" an interface public class Apple extends Edible { } // compile error // ✅ CORRECT — a class "implements" an interface public class Apple extends Fruit implements Edible { } // Note: An interface CAN extend another interface using "extends"! public interface Grillable extends Edible { // ← this is correct! int getGrillTime(); }
Mistake 4: Declaring instance variables (non-constants) in an interface
📄 Example
public interface Edible { // ❌ WRONG — cannot have instance variables private String name; // compile error int calories = 0; // ← this is NOT a variable; it is a constant! // implicitly: public static final int calories = 0 // ✅ CORRECT — only constants (public static final) int MAX_CALORIES = 2000; // constant — shared, immutable // ✅ CORRECT — abstract method String howToEat(); }
Mistake 5: Confusing Interface with Abstract Class

These two are different tools — do not mix them up:

Feature Abstract Class Interface
Instance variables ✅ Yes ❌ No (only constants)
Concrete methods ✅ Yes ❌ No (Java 7 and below)
Constructor ✅ Yes ❌ No
Multiple allowed per class ❌ No — one only ✅ Yes — many!
Represents Incomplete identity Shared behavior
Keyword used by class extends implements
Use when... Objects share identity and some common code Unrelated objects share a behavior

Summary — What We Learned Today

🔗
Interface = Behavior
An interface defines what an object CAN DO, not what it IS. It captures shared behavior across unrelated classes.
💎
Diamond Problem
Java forbids multiple class inheritance to avoid ambiguity. Interfaces solve this by having no state — the class always provides the implementation.
📋
Contract / Promise
Interfaces enable parallel development. They guarantee behavioral compatibility between independently developed modules.
👑
Polymorphic Type
An interface is a valid data type. An Edible[] holds only Edible objects — precise, type-safe polymorphism without a common class ancestor.
📚
Interface Rules
All methods: public abstract. All variables: public static final. No constructor. No instance variables. Use the "implements" keyword.
Multiple Interfaces
A class can implement many interfaces simultaneously. This is Java's safe, flexible answer to the need for multiple behaviors.
📌 The Complete Definition

A Java interface is a class-like construct that defines a set of abstract behaviors (public abstract methods) and constants (public static final variables). It cannot be instantiated directly. A class that implements an interface must override all its abstract methods. An interface can be used as a polymorphic data type, enabling objects of completely unrelated classes to be treated uniformly based on their shared behavior.

Quick Reference Interface Syntax Cheat Sheet

👁︎ Hide Code — Interface Syntax Cheat Sheet
// ── 1. DEFINING AN INTERFACE ───────────────────────────────── public interface MyInterface { int CONSTANT = 42; // public static final int ReturnType methodOne(parameters); // public abstract void methodTwo(); // public abstract } // ── 2. IMPLEMENTING AN INTERFACE ───────────────────────────── public class MyClass extends ParentClass implements Interface1, Interface2 { // multiple OK! @Override public ReturnType methodOne(parameters) { // provide implementation } @Override public void methodTwo() { // provide implementation } } // ── 3. USING AN INTERFACE AS A DATA TYPE ───────────────────── Interface1 ref = new MyClass(); // polymorphic variable Interface1[] array = new Interface1[5]; // polymorphic array // ── 4. AN INTERFACE CAN EXTEND ANOTHER INTERFACE ───────────── public interface ChildInterface extends ParentInterface { void extraMethod(); // adds more abstract methods }
🎨 Code Block Theme