Topic Note: Interfaces & the Interface Challenge (Part 2 of Section 11)¶
Course: Java Programming Masterclass — Tim Buchalka (Udemy)
Section: 11 — Mastering Abstraction & Interfaces (Lectures 8–16)
Status: Complete
Learning Objectives¶
By the end of this part, you should be able to:
- Declare and implement interfaces in Java
- Understand implicit modifiers on interface members (
public,abstract,static,final) - Implement multiple interfaces on a single class
- Use interfaces as reference types for polymorphism
- Extend interfaces using
extends(including multiple inheritance of type) - Have records, enums, and classes all implement interfaces
- Declare and use constants (public static final fields) on interfaces
- Apply the "Coding to an Interface" best practice
- Use default methods (JDK 8) for backwards-compatible interface evolution
- Use static methods (JDK 8) as interface helper utilities
- Use private methods (JDK 9) for code reuse within interfaces
- Compare and contrast interface vs abstract class design choices
- Solve the Mappable Interface Challenge using all interface features
1. What Is an Interface?¶
An interface is not a class — it's a special type that acts as a contract between the class and client code, enforced by the compiler. By declaring that it implements an interface, a class promises to provide implementations of all the abstract methods the interface defines.
Key Insight: Interfaces Unite Unrelated Types¶
Unlike abstract classes (which model "is-a" family relationships), interfaces let you group completely unrelated types by shared behavior:
flowchart TD
subgraph interface[" FlightEnabled Interface "]
FE["takeOff() fly() land()"]
end
B["Bird\n(extends Animal)"] --> interface
J["Jet\n(no parent class)"] --> interface
D["DragonFly\n(record)"] --> interface
S["Satellite\n(implements OrbitEarth)"] --> interface
A Bird, Jet, DragonFly, and Satellite have almost nothing in common — yet they can all be treated uniformly as
FlightEnabledobjects.
2. Declaring and Implementing Interfaces¶
Basic Declaration¶
interface FlightEnabled {
void takeOff(); // Implicitly public and abstract
void land(); // No body — ends with ;
void fly();
}
interface Trackable {
void track();
}
Implementing Interfaces¶
A class uses the implements keyword. It can implement multiple interfaces (separated by commas), and it can also extend a class at the same time:
public class Bird extends Animal implements FlightEnabled, Trackable {
@Override
public void move() {
System.out.println("Flaps its wings");
}
@Override
public void takeOff() {
System.out.println(getClass().getSimpleName() + " takes off");
}
@Override
public void land() {
System.out.println(getClass().getSimpleName() + " lands");
}
@Override
public void fly() {
System.out.println(getClass().getSimpleName() + " flies");
}
@Override
public void track() {
System.out.println(getClass().getSimpleName() + "'s coordinates recorded");
}
}
Key rule: extends comes FIRST, implements comes SECOND in the declaration.
classDiagram
class Animal {
<<abstract>>
+move()* void
}
class FlightEnabled {
<<interface>>
+takeOff() void
+land() void
+fly() void
}
class Trackable {
<<interface>>
+track() void
}
class Bird {
+move() void
+takeOff() void
+land() void
+fly() void
+track() void
}
class Jet {
+takeOff() void
+land() void
+fly() void
+track() void
}
class Truck {
+track() void
}
Animal <|-- Bird
FlightEnabled <|.. Bird
Trackable <|.. Bird
FlightEnabled <|.. Jet
Trackable <|.. Jet
Trackable <|.. Truck
3. Implicit Modifiers — The Interface Rules¶
Methods Without a Body¶
On an interface, any method declared without a body is automatically public and abstract. All three of these declarations are equivalent:
public abstract void takeOff(); // Explicit — but redundant
abstract void takeOff(); // Partly explicit — still redundant
void takeOff(); // Preferred — clean and simple
Access Modifier Restrictions
- Methods without a body are always public — you CANNOT use
protectedorprivateon abstract interface methods - If you omit access modifiers on a class member → it's package-private
- If you omit access modifiers on an interface member → it's public
- This is an important difference to remember!
Fields on Interfaces¶
Any field declared on an interface is implicitly public static final — making it a constant:
interface FlightEnabled {
// These are ALL identical — public static final is implied
double MILES_TO_KM = 1.60934;
public static final double KM_TO_MILES = 0.621371; // Redundant modifiers
}
Access them like any static constant:
Why only constants? An interface never gets instantiated and doesn't participate in inheritance. There's no object to hold instance state — so fields must be static and final.
4. Multiple Implementations & Polymorphism¶
The Power: One Object, Many Types¶
When a class implements interfaces and extends a class, its instances can be assigned to any of those types:
Bird bird = new Bird(); // Bird type — all methods available
Animal animal = bird; // Animal type — only move()
FlightEnabled flier = bird; // FlightEnabled — takeOff(), fly(), land()
Trackable tracked = bird; // Trackable — only track()
flowchart LR
subgraph bird_obj[" bird object "]
M["move()"]
T["takeOff()"]
F["fly()"]
L["land()"]
TR["track()"]
end
A["Animal variable"] -.-> M
FE["FlightEnabled variable"] -.-> T
FE -.-> F
FE -.-> L
TK["Trackable variable"] -.-> TR
BD["Bird variable"] -.-> M
BD -.-> T
BD -.-> F
BD -.-> L
BD -.-> TR
The declared type determines which methods you can call. Even though
birdhas all methods, aFlightEnabled fliervariable can only callFlightEnabledmethods.
Method Using Interface Types¶
private static void inFlight(FlightEnabled flier) {
flier.takeOff();
flier.fly();
if (flier instanceof Trackable tracked) {
tracked.track(); // Only if it's also Trackable
}
flier.land();
}
// Works with ANY FlightEnabled object:
inFlight(new Bird()); // Bird behavior
inFlight(new Jet()); // Jet behavior
Truck — Implementing Only the Interface It Needs¶
public class Truck implements Trackable {
@Override
public void track() {
System.out.println(getClass().getSimpleName() + "'s coordinates recorded");
}
}
A Truck can be tracked but can't fly — it only implements Trackable. Interfaces let you mix and match behaviors as needed.
5. Interface Extending Interface¶
An interface can extend another interface (not implement — that's only for classes):
Any class implementing OrbitEarth must implement:
achieveOrbit()— from OrbitEarthtakeOff(),fly(),land()— from FlightEnabled (inherited)
Important rules:
| Rule | Description |
|---|---|
Interface uses extends, NOT implements |
interface B implements A → ❌ compile error |
| Can extend multiple interfaces | interface C extends A, B → ✅ valid |
| Classes implement, interfaces extend | Different keywords for different relationships |
Records and Enums Can Implement Interfaces¶
// Record implementing FlightEnabled
record DragonFly(String name, String type) implements FlightEnabled {
@Override
public void takeOff() { }
@Override
public void land() { }
@Override
public void fly() { }
}
// Enum implementing Trackable
enum FlightStages implements Trackable {
GROUNDED, LAUNCH, CRUISE, DATA_COLLECTION;
@Override
public void track() {
if (this != GROUNDED) {
System.out.println("Monitoring " + this);
}
}
public FlightStages getNextStage() {
FlightStages[] allStages = values();
return allStages[(ordinal() + 1) % allStages.length];
}
}
Records and enums can implement interfaces but CANNOT extend classes (abstract or otherwise). This makes interfaces the only way to add shared behavior contracts to records and enums.
6. Coding to an Interface — Best Practice¶
The Problem: Tight Coupling to Specific Types¶
// BAD: Method locked to ArrayList
private static void triggerFliers(ArrayList<FlightEnabled> fliers) {
for (var flier : fliers) flier.takeOff();
}
// If you change to LinkedList, ALL methods break!
LinkedList<FlightEnabled> fliers = new LinkedList<>();
triggerFliers(fliers); // ❌ Cannot pass LinkedList to ArrayList parameter
The Solution: Use the Interface Type¶
// GOOD: Method accepts ANY List implementation
private static void triggerFliers(List<FlightEnabled> fliers) {
for (var flier : fliers) flier.takeOff();
}
// Both work now — no refactoring needed!
ArrayList<FlightEnabled> list1 = new ArrayList<>();
LinkedList<FlightEnabled> list2 = new LinkedList<>();
triggerFliers(list1); // ✅
triggerFliers(list2); // ✅
flowchart TD
subgraph bad[" ❌ Tight Coupling "]
AL["ArrayList parameter"]
AL -.-x LL1["LinkedList — won't compile"]
end
subgraph good[" ✅ Coding to Interface "]
LI["List parameter"]
LI --> AL2["ArrayList — works"]
LI --> LL2["LinkedList — works"]
LI --> VEC["Vector — works"]
end
Where to Apply This¶
Use interface types as the reference type for:
- ✅ Method parameters:
List<T>instead ofArrayList<T> - ✅ Method return types: return
List<T>notArrayList<T> - ✅ Local variables:
List<T> items = new ArrayList<>() - ✅ Class fields:
private List<T> items
Swapping implementations becomes a one-line change instead of a system-wide refactor.
7. JDK 8 Enhancements: Default & Static Methods¶
The Backwards Compatibility Problem¶
Before JDK 8, adding a new abstract method to an interface broke every class implementing it:
// Adding this to FlightEnabled...
FlightStages transition(FlightStages stage); // Abstract
// ...breaks Bird, Jet, Satellite, DragonFly — ALL must now implement it!
Default Methods (Extension Methods)¶
The default keyword lets you provide a concrete method on an interface with a body:
interface FlightEnabled {
void takeOff();
void land();
void fly();
// Default method — has a body, won't break existing implementations
default FlightStages transition(FlightStages stage) {
FlightStages nextStage = stage.getNextStage();
System.out.println("Transitioning from " + stage + " to " + nextStage);
return nextStage;
}
}
Key properties of default methods:
| Property | Detail |
|---|---|
| Has a method body | Must have { }, even if empty |
Uses default keyword |
NOT the same as package-private default access |
| Won't break existing classes | Existing implementations inherit the default behavior |
| Can be overridden | Subclasses can override with their own version |
Can access this |
At runtime, this refers to the implementing object |
Call from override with InterfaceName.super |
NOT just super — must qualify with interface name |
Overriding a Default Method¶
Three choices (same as overriding a class method):
- Don't override — inherit the default behavior
- Override completely — ignore the default
- Override and call the default — combine behaviors
public class Jet implements FlightEnabled, Trackable {
@Override
public FlightStages transition(FlightStages stage) {
System.out.println(getClass().getSimpleName() + " transitioning");
// Must qualify super with interface name!
return FlightEnabled.super.transition(stage); // ✅
// return super.transition(stage); // ❌ Compile error!
}
}
Why
FlightEnabled.super.transition()? Because interfaces aren't part of the class hierarchy. Plainsuperrefers to the parent class (which isObjectfor Jet). You must tell Java which interface's default method you mean.
Public Static Methods (JDK 8)¶
Static helper methods can live directly on the interface:
interface OrbitEarth extends FlightEnabled {
void achieveOrbit();
// Public static helper — called with OrbitEarth.log(...)
static void log(String description) {
var today = new java.util.Date();
System.out.println(today + ": " + description);
}
}
// Usage:
OrbitEarth.log("Testing " + new Satellite());
Before JDK 8, you'd need a separate helper class for static utilities related to an interface (like Collections for the Collection interface). Now they can be on the interface itself.
8. JDK 9 Enhancement: Private Methods¶
JDK 9 added private methods (both static and non-static) to interfaces, enabling code reuse between concrete methods:
interface OrbitEarth extends FlightEnabled {
void achieveOrbit();
// Private static — accessible by static, default, and private methods
private static void log(String description) {
var today = new java.util.Date();
System.out.println(today + ": " + description);
}
// Private non-static — supports default methods
private void logStage(FlightStages stage, String description) {
description = stage + ": " + description;
log(description); // Calls private static method
}
// Default method overriding parent interface's default
@Override
default FlightStages transition(FlightStages stage) {
FlightStages nextStage = FlightEnabled.super.transition(stage);
logStage(stage, "Transitioning to " + nextStage); // Uses private method
return nextStage;
}
}
Method Accessibility Matrix on Interfaces¶
| Method Type | Can call public static? | Can call default? | Can call private static? | Can call private non-static? |
|---|---|---|---|---|
| Public static | ✅ | ❌ | ✅ | ❌ |
| Default | ✅ | ✅ | ✅ | ✅ |
| Private static | ✅ | ❌ | ✅ | ❌ |
| Private non-static | ✅ | ✅ | ✅ | ✅ |
Complete Satellite Class¶
class Satellite implements OrbitEarth {
FlightStages stage = FlightStages.GROUNDED;
public void achieveOrbit() {
transition("Orbiting achieved!");
}
@Override
public void takeOff() {
transition("Taking off");
}
@Override
public void land() {
transition("Landing");
}
@Override
public void fly() {
achieveOrbit();
transition("Data Collection while Orbiting");
}
// Overloaded (not overriding!) — different signature
public void transition(String description) {
System.out.println(description);
stage = transition(stage); // Calls OrbitEarth's default method
stage.track(); // Each stage is Trackable
}
}
9. Interface vs Abstract Class — Full Comparison¶
| Feature | Abstract Class | Interface |
|---|---|---|
| Instantiation | ❌ Cannot instantiate | ❌ Cannot instantiate |
| Constructors | ✅ Yes — called by subclasses | ❌ No constructors |
| Inherits from Object | ✅ Implicitly extends java.lang.Object |
❌ Not a class at all |
| Keyword to use | extends (one only) |
implements (many) |
| Multiple inheritance | ❌ Single class only | ✅ Can implement many interfaces |
| Instance fields | ✅ Any access modifier | ❌ Only public static final (constants) |
| Abstract methods | ✅ Any access except private |
✅ Implicitly public abstract |
| Concrete methods | ✅ Any access modifier | ✅ default, static, private only |
| Who can use it | Classes (via extends) |
Classes, Records, Enums (via implements) |
| Relationship modeled | "is-a" (family hierarchy) | "can-do" (capability/behavior) |
When to Use Which¶
flowchart TD
Q1["Do classes share state\n(instance fields)?"] -->|Yes| AC["Use Abstract Class"]
Q1 -->|No| Q2["Do classes share a\nfamily relationship?"]
Q2 -->|Yes| AC
Q2 -->|No| Q3["Are the classes otherwise\nunrelated?"]
Q3 -->|Yes| IF["Use Interface"]
Q3 -->|No| Q4["Do you need\nmultiple behaviors?"]
Q4 -->|Yes| IF
Q4 -->|No| EITHER["Either works —\nprefer Interface"]
Use an Abstract Class when:
- Classes are closely related (Animal → Dog, Mammal → Horse)
- You want shared instance fields (type, size, weight)
- You need non-public access on methods (protected, package-private)
- You want a default implementation that relies on instance state
Use an Interface when:
- Unrelated classes need the same behavior (Bird, Jet, DragonFly all fly)
- You want multiple behavior contracts on one class
- You want to decouple "what" from "how"
- Records and enums need to participate
- You're designing for future extensibility
Summary: An abstract class provides a common definition as a base class for closely related types. An interface decouples the "what" from the "how" and makes different types behave in similar ways.
10. Interface Challenge: The Mappable System¶
Problem Statement¶
Create a Mappable interface that can be added to any existing class so it can produce GeoJSON-like output for a mapping application. The interface should support:
- Three abstract methods:
getLabel(),getShape(),getMarker() - A constant
JSON_PROPERTYtemplate string - A
defaultmethodtoJSON()that formats the interface properties - A
staticmethodmapIt()that prints the full JSON output - Two concrete classes:
Building(POINT) andUtilityLine(LINE)
Class Diagram¶
classDiagram
class Geometry {
<<enum>>
LINE
POINT
POLYGON
}
class Color {
<<enum>>
BLACK
BLUE
GREEN
ORANGE
RED
}
class PointMarker {
<<enum>>
CIRCLE
PUSH_PIN
STAR
SQUARE
TRIANGLE
}
class LineMarker {
<<enum>>
DASHED
DOTTED
SOLID
}
class Mappable {
<<interface>>
+String JSON_PROPERTY$
+getLabel() String
+getShape() Geometry
+getMarker() String
+toJSON() String
+mapIt(Mappable)$ void
}
class Building {
-String name
-UsageType usage
+Building(name, usage)
+getLabel() String
+getShape() Geometry
+getMarker() String
+toJSON() String
}
class UtilityLine {
-String name
-UtilityType type
+UtilityLine(name, type)
+getLabel() String
+getShape() Geometry
+getMarker() String
+toJSON() String
}
Mappable <|.. Building
Mappable <|.. UtilityLine
The Mappable Interface¶
enum Geometry {LINE, POINT, POLYGON}
enum Color {BLACK, BLUE, GREEN, ORANGE, RED}
enum PointMarker {CIRCLE, PUSH_PIN, STAR, SQUARE, TRIANGLE}
enum LineMarker {DASHED, DOTTED, SOLID}
public interface Mappable {
// Constant — implicitly public static final
String JSON_PROPERTY = """
"properties": {%s}\s""";
// 3 abstract methods — classes MUST implement these
String getLabel();
Geometry getShape();
String getMarker();
// Default method — provides base JSON formatting
default String toJSON() {
return """
"type": "%s", "label": "%s", "marker": "%s"\s"""
.formatted(getShape(), getLabel(), getMarker());
}
// Static helper — prints full JSON output for any Mappable
static void mapIt(Mappable mappable) {
System.out.println(JSON_PROPERTY.formatted(mappable.toJSON()));
}
}
Interface features used:
| Feature | How Used |
|---|---|
| Constant | JSON_PROPERTY — template for all mappable output |
| Abstract methods | getLabel(), getShape(), getMarker() — forced on all implementations |
| Default method | toJSON() — base formatting, can be overridden to add more properties |
| Static method | mapIt() — utility to print any Mappable's JSON |
Building — A POINT on the Map¶
enum UsageType {ENTERTAINMENT, RESIDENTIAL, GOVERNMENT, SPORTS}
public class Building implements Mappable {
private String name;
private UsageType usage;
public Building(String name, UsageType usage) {
this.name = name;
this.usage = usage;
}
@Override
public String getLabel() {
return name + " (" + usage + ")";
}
@Override
public Geometry getShape() {
return Geometry.POINT;
}
@Override
public String getMarker() {
return switch (usage) {
case ENTERTAINMENT -> Color.GREEN + " " + PointMarker.TRIANGLE;
case GOVERNMENT -> Color.RED + " " + PointMarker.STAR;
case RESIDENTIAL -> Color.BLUE + " " + PointMarker.SQUARE;
case SPORTS -> Color.ORANGE + " " + PointMarker.PUSH_PIN;
default -> Color.BLACK + " " + PointMarker.CIRCLE;
};
}
@Override
public String toJSON() {
return Mappable.super.toJSON() + """
, "name": "%s", "usage": "%s"\s""".formatted(name, usage);
}
}
UtilityLine — A LINE on the Map¶
enum UtilityType {ELECTRICAL, FIBER_OPTIC, GAS, WATER}
public class UtilityLine implements Mappable {
private String name;
private UtilityType type;
public UtilityLine(String name, UtilityType type) {
this.name = name;
this.type = type;
}
@Override
public String getLabel() {
return name + " (" + type + ")";
}
@Override
public Geometry getShape() {
return Geometry.LINE;
}
@Override
public String getMarker() {
return switch (type) {
case ELECTRICAL -> Color.RED + " " + LineMarker.DASHED;
case FIBER_OPTIC -> Color.GREEN + " " + LineMarker.DOTTED;
case GAS -> Color.ORANGE + " " + LineMarker.SOLID;
case WATER -> Color.BLUE + " " + LineMarker.SOLID;
default -> Color.BLACK + " " + LineMarker.SOLID;
};
}
@Override
public String toJSON() {
return Mappable.super.toJSON() + """
, "name": "%s", "utility": "%s"\s""".formatted(name, type);
}
}
The Main Class — Coding to the Interface¶
public class Main {
public static void main(String[] args) {
// Coding to the interface: List<Mappable>, not ArrayList<Building>
List<Mappable> mappables = new ArrayList<>();
// Buildings — POINT geometry
mappables.add(new Building("Sydney Town Hall", UsageType.GOVERNMENT));
mappables.add(new Building("Sydney Opera House", UsageType.ENTERTAINMENT));
mappables.add(new Building("Stadium Australia", UsageType.SPORTS));
// Utility Lines — LINE geometry
mappables.add(new UtilityLine("College St", UtilityType.FIBER_OPTIC));
mappables.add(new UtilityLine("Olympic Blvd", UtilityType.WATER));
// One loop handles ALL Mappable types
for (var m : mappables) {
Mappable.mapIt(m);
}
}
}
Sample Output¶
"properties": {"type": "POINT", "label": "Sydney Town Hall (GOVERNMENT)", "marker": "RED STAR", "name": "Sydney Town Hall", "usage": "GOVERNMENT"}
"properties": {"type": "POINT", "label": "Sydney Opera House (ENTERTAINMENT)", "marker": "GREEN TRIANGLE", "name": "Sydney Opera House", "usage": "ENTERTAINMENT"}
"properties": {"type": "LINE", "label": "College St (FIBER_OPTIC)", "marker": "GREEN DOTTED", "name": "College St", "utility": "FIBER_OPTIC"}
How toJSON() Override Works¶
flowchart TD
subgraph Building_toJSON["Building.toJSON()"]
B1["Mappable.super.toJSON()"]
B2["+ name and usage fields"]
B1 --> B2
end
subgraph Default_toJSON["Mappable default toJSON()"]
D1["Calls getShape() → POINT"]
D2["Calls getLabel() → name + usage"]
D3["Calls getMarker() → Color + PointMarker"]
D1 --> D2 --> D3
end
Building_toJSON --> Default_toJSON
subgraph mapIt["Mappable.mapIt()"]
M1["JSON_PROPERTY.formatted(...)"]
M2["Wraps in properties: curly brackets"]
M1 --> M2
end
mapIt --> Building_toJSON
Common Pitfalls¶
1. Using protected on Interface Methods¶
interface FlightEnabled {
protected void takeOff(); // ❌ Compile error!
// "Modifier 'protected' not allowed here"
}
Fix: Interface abstract methods are always public. Don't specify an access modifier, or use public (which is redundant).
2. Forgetting public When Implementing Interface Methods¶
// In interface (implicitly public):
interface Mappable {
String getLabel(); // public abstract
}
// In implementing class:
class Building implements Mappable {
String getLabel() { ... } // ❌ "Attempting to assign weaker access"
}
Fix: Always declare implementing methods as public, since interface methods are implicitly public:
3. Using super Instead of InterfaceName.super¶
@Override
public FlightStages transition(FlightStages stage) {
return super.transition(stage); // ❌ "Cannot resolve method in Object"
return FlightEnabled.super.transition(stage); // ✅ Correct!
}
Why: Interfaces are NOT part of the class hierarchy. super always refers to the parent class.
4. Interface Using implements Instead of extends¶
interface OrbitEarth implements FlightEnabled { } // ❌ Compile error!
interface OrbitEarth extends FlightEnabled { } // ✅ Correct!
5. Adding Abstract Methods to Published Interfaces¶
// Before: interface has 3 methods, 50 classes implement it
// After: add a 4th abstract method → ALL 50 classes break!
Fix: Use a default method instead — existing implementations inherit it without changes.
Key Takeaways¶
- Interfaces are contracts, not classes — they define what without how
- Multiple interfaces per class — one class can implement as many as it needs, unlike single inheritance
- Implicit modifiers matter — interface methods are
public abstractby default; fields arepublic static final - "Coding to an Interface" is a best practice — use
List<T>notArrayList<T>in declarations - Default methods (JDK 8) solve backwards compatibility — add new behavior without breaking existing implementations
- Static methods (JDK 8) put helper utilities directly on the interface type
- Private methods (JDK 9) enable code reuse between default methods
- Records and enums can implement interfaces but cannot extend classes
- Interface vs Abstract Class is not either/or — use abstract classes for shared state among family, interfaces for shared behavior among strangers
InterfaceName.super.method()is required to call default methods from overrides — plainsuperwon't work
Quick Reference¶
Interface Method Types Summary¶
| JDK | Method Type | Has Body? | Modifier | Overridable? |
|---|---|---|---|---|
| 1.0 | Abstract | ❌ | public abstract (implicit) |
Must implement |
| 8 | Default | ✅ | default |
✅ Optional |
| 8 | Public Static | ✅ | static |
❌ |
| 9 | Private | ✅ | private |
❌ |
| 9 | Private Static | ✅ | private static |
❌ |
Interface Evolution Timeline¶
timeline
title Java Interface Evolution
JDK 1 : Abstract methods only
: Public static final fields only
JDK 8 : Default methods (extension methods)
: Public static methods
JDK 9 : Private methods
: Private static methods
Related Notes¶
| Part | Topic | Link |
|---|---|---|
| 1 | Abstract Classes (Section 11, Lectures 1–7) | Part 1 — Abstract Classes |
| 2 | Interfaces & Interface Challenge (Section 11, Lectures 8–16) | You are here |
| 3 | Generics: Classes, Bounds & Layer Challenge (Section 12, Lectures 1–6) | Part 3 — Generics |
| 4 | Comparable, Comparator, Wildcards, Type Erasure & Final Challenge (Section 12, Lectures 7–12) | Part 4 — Advanced Generics |
| 5 | Nested Classes, Local Types & Anonymous Classes (Section 13) | Part 5 — Nested Classes |
References¶
- Course: Tim Buchalka — Java Programming Masterclass (Section 11, Lectures 8–16)
- API: java.lang.Comparable (Java 17)
- Guide: Interfaces (Oracle Tutorial)
- Guide: Default Methods (Oracle Tutorial)
- Book: Effective Java — Item 20: Prefer interfaces to abstract classes
- Book: Effective Java — Item 21: Design interfaces for posterity
Last Updated: 2026-02-24 | Confidence: 9/10