Interfaces & Abstract Classes
java1-5 closed with a promise: state can only ever come from one superclass, but behavior can still come from multiple sources — through interfaces. This chapter delivers on that.
Interfaces — The Contract
An interface declares method signatures with no body and no instance fields — a pure contract. A class implements it and must supply real bodies for every abstract method it declares.
A Class Can implements Many Interfaces
This is exactly where "multiple sources of behavior" comes back from java1-5. extends is capped at one superclass; implements has no such cap at all — a single class can satisfy as many interface contracts as it genuinely needs to.
Default Methods (Java 8+)
Since Java 8, an interface method can carry a default body — implementing classes inherit it automatically and may override it if they need different behavior. This is a genuine convergence point with Rust: rust2-2's own trait default methods work the same way, behavior supplied by the contract itself without requiring every implementer to repeat it.
Abstract Classes
Unlike an interface, an abstract class can hold real fields, constructors, and fully concrete methods alongside abstract ones. It still follows java1-5's own single-inheritance rule — a class extends at most one abstract class, exactly the same as any other class.
Interface vs. Abstract Class — When to Use Which
An interface answers "can this do X?" with no shared state at all. An abstract class answers "is this genuinely a kind of Y?" and gets to share real implementation and state across every subclass. A class can implement many interfaces but extend only one abstract class — the choice usually follows from that asymmetry directly.
The Diamond Problem, Returning For Behavior Alone
Two interfaces can both supply conflicting default implementations of the same method — a real, narrow reappearance of cpp3-1's diamond problem, scoped to behavior only, since interfaces never carry state. Java doesn't guess which one wins: the implementing class is required to override the method itself and resolve the conflict explicitly, or the code simply fails to compile.
| Mechanism | C++ (cpp3-1) | Rust (rust2-2) | Java |
|---|---|---|---|
| Multiple inheritance of state | allowed — causes the diamond problem | never possible — structs don't inherit | never possible — single extends only |
| Multiple sources of behavior | multiple inheritance (same mechanism as state) | traits, no state carried | interfaces, no state carried |
| Conflicting default behavior | virtual inheritance resolves it structurally | compile error — must be resolved explicitly | compile error — must be overridden explicitly |
default method with the same signature, Java refuses to guess which one applies — the class must override that method itself, even if only to explicitly pick one interface's version via InterfaceName.super.methodName().
Coding Challenges
Write an interface Printable with an abstract method print() and a default method printTwice() that calls print() twice, then a class implementing Printable that only supplies print().
📄 View solutionWrite an abstract class Employee with a protected name field, a constructor, an abstract method pay(), and a concrete method summary() that calls pay(). Then write a Manager subclass that supplies pay().
📄 View solutionWrite two interfaces that each declare a default method with the identical signature but different bodies, then a class that implements both. Show the resulting compile error, then fix it by overriding the method explicitly.
📄 View solutionChapter 6 Quick Reference
- Interfaces declare method contracts with no state; a class can implements as many as it needs, unlike extends's single-superclass cap
- default methods (Java 8+) give an interface a real method body — a genuine convergence point with Rust's own trait default methods
- Abstract classes can hold state, constructors, and concrete methods alongside abstract ones — but still follow single inheritance
- Interface = "can do," no shared state; abstract class = "is a," shared state and implementation
- Conflicting default methods from two interfaces force an explicit override — Java never silently picks a winner
- Next chapter: exception handling — checked vs. unchecked exceptions