Free degree-level programming lessons for careful independent study.

Degree Level Programmes · Programming 2 · Lesson 10

Interfaces and Higher-Level Abstractions

Use interfaces and polymorphism to separate what code needs from how it is implemented.

Lesson Overview

Use interfaces and polymorphism to separate what code needs from how it is implemented.

Portfolio focus: Create a Notifier interface.

ConceptAbstraction
Run fileInterfacesAndHigherAbstractionsDemo.java
BaselineYour build passed.
Evidence3 tasks

Starter: think before typing

Before running this abstraction example, find the line where the main idea becomes active. Write a prediction: what must already be true for that line to work, and what should be different after it runs? The checked run ends with `Your build passed.`; predict how the focus line helps produce that evidence.

Learning Objectives

  • Define a Java interface.
  • Use polymorphism through interface references.
  • Explain dependency on behaviour rather than concrete classes.
  • Design a swappable component.

Learning Outcomes

  • By the end of the lesson, you can define a Java interface.
  • By the end of the lesson, you can use polymorphism through interface references.
  • By the end of the lesson, you can explain dependency on behaviour rather than concrete classes.
  • By the end of the lesson, you can design a swappable component.

Why this idea exists

Interfaces express one of programming's most powerful ideas: depend on what something can do, not exactly what concrete thing it is. This supports substitution, testing and flexible design.

This style developed from broader abstraction principles in software engineering. As systems grew, programmers needed ways to reduce coupling so one implementation could change without forcing changes everywhere.

In Java, an interface is a contract. Used well, it lets a program talk to a capability such as notification, storage or scoring without caring whether the implementation uses email, a file, a database or a mock object.

Deep dive

Mechanism in this example

The important mechanism is visible around `Notifier notifier = new ConsoleNotifier();`. Read it as a concrete move in the program, not as decorative syntax: identify what value, object, branch, call or boundary is being created at that point.

Design pressure

In Java, an interface is a contract. Used well, it lets a program talk to a capability such as notification, storage or scoring without caring whether the implementation uses email, a file, a database or a mock object.

Failure mode to watch

For Interfaces and Higher-Level Abstractions, deliberately disturb the assumption behind `Notifier notifier = new ConsoleNotifier();`: use an awkward value, missing input, wrong order of calls or boundary case. The useful question is how that disturbance exposes a weakness in the abstraction design.

Extension step

Extend the example by doing this: Write two implementations. The point is to make one small change that forces you to revisit the concept, rather than adding unrelated features.

Portfolio standard

The portfolio note should not repeat the lesson wording. It should show the edited code, the run result, and your own explanation of this evidence: use the interface in a service class.

Lesson visual

Photo of interchangeable tool heads labelled interface implementations, overlaid with Java interface and class cards.
Photo of interchangeable tool heads labelled interface implementations, overlaid with Java interface and class cards.Download visual

Type this and run it

Create InterfacesAndHigherAbstractionsDemo.java, type the program, and run it before changing anything. This section is about reproducing the checked baseline.

public class InterfacesAndHigherAbstractionsDemo {
  public static void main(String[] args) {
    Notifier notifier = new ConsoleNotifier();
    notifier.send("Your build passed.");
  }
}

interface Notifier {
  void send(String message);
}

class ConsoleNotifier implements Notifier {
  public void send(String message) {
    System.out.println(message);
  }
}

Build and run it with:

javac InterfacesAndHigherAbstractionsDemo.java && java InterfacesAndHigherAbstractionsDemo

Expected baseline: Your build passed.

Run the code in your browser

Use the editor as an experiment surface. First run the checked version, then make one small change to the part of the program that demonstrates abstraction and compare the new behaviour with the reference output.

Line-by-line explanation

Read the code as a sequence of responsibilities. The focus line for this lesson is Notifier notifier = new ConsoleNotifier();; the surrounding lines prepare it, use its result or make the behaviour observable.

public class InterfacesAndHigherAbstractionsDemo {

This names the runnable class for the Interfaces and Higher-Level Abstractions example, giving the compiler and JVM one clear unit to build.

public static void main(String[] args) {

This is the program entry point. In Interfaces and Higher-Level Abstractions, it keeps the demonstration of abstraction in one traceable starting script.

Notifier notifier = new ConsoleNotifier();

This introduces notifier as named state for Interfaces and Higher-Level Abstractions. Later lines can read, update, pass or print that specific value as evidence.

notifier.send("Your build passed.");

This calls notifier.send with "Your build passed." in Interfaces and Higher-Level Abstractions. Look for the method definition to see what work actually happens.

}

This closes the innermost Interfaces and Higher-Level Abstractions block, so the immediately preceding method, branch or loop has finished.

}

This closes the outer Interfaces and Higher-Level Abstractions structure, returning the reader to the surrounding class or file.

interface Notifier {

This declares the Interfaces and Higher-Level Abstractions behavioural contract; later code can depend on the capability instead of one fixed implementation.

void send(String message);

This declares send for Interfaces and Higher-Level Abstractions. The semicolon matters because an interface gives the contract here, not the body.

}

This closing brace number 3 completes another layer of the Interfaces and Higher-Level Abstractions source structure Java has been checking.

class ConsoleNotifier implements Notifier {

This starts a supporting class so Interfaces and Higher-Level Abstractions can separate the lesson idea into its own named responsibility.

public void send(String message) {

This starts send, a named Interfaces and Higher-Level Abstractions operation. Its parameters describe what information comes in; its body decides what work is done.

System.out.println(message);

This prints message as the observable evidence for Interfaces and Higher-Level Abstractions. The output lets the learner check whether the abstraction idea behaved as predicted.

}

This closing brace number 4 completes another layer of the Interfaces and Higher-Level Abstractions source structure Java has been checking.

}

This closing brace number 5 completes another layer of the Interfaces and Higher-Level Abstractions source structure Java has been checking.

Worked example

From code to explanation

Problem: Use Interfaces and Higher-Level Abstractions to complete a small portfolio-quality step: Create a Notifier interface.

Method: Locate the line `Notifier notifier = new ConsoleNotifier();`, explain the exact role it plays, then decide what you would change to extend the example without changing the whole program.

Reveal worked answer

The checked run should produce `Your build passed.`. A strong answer links the result back to abstraction: what was created, selected, stored, called or protected, and why that matters for the portfolio task.

Trace the program

Before: Before the key operation, identify the relevant value, object, branch or resource that the abstraction concept depends on.

During: Trace `Notifier notifier = new ConsoleNotifier();` as the Interfaces and Higher-Level Abstractions example executes. Say whether that operation creates data, checks a condition, calls behaviour, stores information or crosses a boundary.

After: Compare the run with the expected evidence: `Your build passed.`.

Change: Now write two implementations, run again, and explain the smallest reason the behaviour changed.

Common misconception

A common mistake in interfaces and higher-level abstractions is treating the example as a finished answer. For abstraction, the important question is narrower: which operation carries the idea, what does it make possible, and what would break if you changed it carelessly?

Quick checks

1. In this Interfaces and Higher-Level Abstractions example, what is the best reason to focus on `Notifier notifier = new ConsoleNotifier();`?

2. Which evidence is strongest after you edit and rerun this example?

How to study this lesson

For Interfaces and Higher-Level Abstractions, predict how abstraction changes the run before you press Run.

Use the first portfolio task as your main edit: Create a Notifier interface.

Use the second task as your variation: Write two implementations.

Finish with evidence, not a diary entry: Use the interface in a service class.

Portfolio Practice

  1. Create a Notifier interface.
  2. Write two implementations.
  3. Use the interface in a service class.

Final self-check

Can you explain the key operation?

Explain the line identified in the quick check in one or two sentences. Your answer should say what it does before the output Your build passed. appears.

Can you justify the portfolio evidence?

Your evidence should include the original run, one edited run, and a short note explaining how the edit affected abstraction.

Study route

Practise abstraction by predicting the Java example, typing it, running it in the browser, tracing the result and saving portfolio evidence.

Next, move into Exceptions and Defensive Programming and carry forward one improvement from this lesson into the next program.