What you'll learn
Beyond plain classes, Java offers specialised type-building tools: interfaces for contracts, enums for fixed sets of constants, records for concise data carriers, and several kinds of nested class. Each removes boilerplate and makes your intent crystal clear.
By the end you'll be able to:
- Define contracts with interfaces and implement several at once
- Add shared behaviour with
defaultandstaticinterface methods - Recognise a functional interface and back it with a lambda
- Model fixed choices with enums (including fields and methods)
- Create immutable data types in one line with records
- Restrict a hierarchy with sealed types and use nested classes
Interfaces
An interface is a pure contract: a list of methods a class promises to provide, with no implementation of its own. A class implements an interface and supplies the bodies. Crucially, a class can implement many interfaces (unlike extends, which allows only one parent) — that's Java's answer to multiple inheritance:
interface Drawable { void draw(); }
interface Clickable { void onClick(); }
class Button implements Drawable, Clickable { // implement MANY
public void draw() { System.out.println("Drawing a button"); }
public void onClick() { System.out.println("Button clicked"); }
}
public class Main {
public static void main(String[] args) {
Button b = new Button();
b.draw();
b.onClick();
}
}Interface
- • A pure contract of what to do
- • A class can implement many
- • No constructors, no instance state
- • Answers "can-do" (Comparable, Runnable)
Abstract class
- • A partial base with shared code
- • A class can extend only one
- • Can have constructors & fields
- • Answers "is-a" (Shape, Animal)
Default, static & private methods
Since Java 8, interfaces can carry default methods — real implementations that every implementer inherits automatically, so you can add behaviour to an interface without breaking existing classes. Interfaces can also have static helper methods and private methods (to share code between defaults). Any variable declared in an interface is implicitly a public static final constant.
interface Greeter {
String name(); // abstract: implementer provides it
default void greet() { // default: has a body, inherited free
System.out.println("Hello, " + name());
}
}
class Person implements Greeter {
public String name() { return "Sara"; }
}
public class Main {
public static void main(String[] args) {
new Person().greet();
}
}Functional interfaces
An interface with exactly one abstract method is a functional interface. These are special because a lambda expression can stand in for one — a compact way to pass behaviour around. The @FunctionalInterface annotation makes the compiler enforce the "one method" rule:
@FunctionalInterface
interface Operation {
int apply(int a, int b); // exactly ONE abstract method
}
public class Main {
public static void main(String[] args) {
Operation add = (a, b) -> a + b; // a lambda!
Operation mul = (a, b) -> a * b;
System.out.println(add.apply(3, 4)); // 7
System.out.println(mul.apply(3, 4)); // 12
}
}Note
Runnable, Comparator, and Predicate are all functional interfaces.Enums
When a value can only be one of a fixed set — days of the week, card suits, order states — use an enum. It gives you type safety (the compiler rejects invalid values) and readable code. Enums can also have fields, constructors, and methods, making them far more powerful than plain constants:
enum Day {
MON, TUE, WED, THU, FRI, SAT, SUN;
boolean isWeekend() {
return this == SAT || this == SUN;
}
}
public class Main {
public static void main(String[] args) {
Day today = Day.SAT;
System.out.println(today); // SAT
System.out.println(today.isWeekend()); // true
}
}enum Planet {
EARTH(9.81), MARS(3.71), MOON(1.62); // each constant calls the constructor
final double gravity;
Planet(double g) { this.gravity = g; }
}
public class Main {
public static void main(String[] args) {
System.out.println(Planet.MARS.gravity);
}
}Records
So often you just need a small, immutable bundle of data — a point, a coordinate, a response object. Traditionally that meant writing dozens of lines of fields, getters, equals, hashCode, and toString. A record (Java 16+) generates all of that from a single line:
A traditional data class
Fields + constructor + getters + equals() + hashCode() + toString() — easily 40+ lines of boilerplate.
The same thing as a record
record Point(int x, int y) {}One line. Java generates the rest for you.
record Point(int x, int y) { } // that's the whole class!
public class Main {
public static void main(String[] args) {
Point p = new Point(3, 4);
System.out.println(p.x()); // auto getter
System.out.println(p); // auto toString
System.out.println(p.equals(new Point(3, 4))); // auto equals
}
}Tip
Sealed classes & interfaces
A sealed type restricts which classes may extend or implement it, using a permits clause. This gives you a closed, known set of subtypes — which pairs beautifully with pattern-matching switch (the compiler knows every case):
sealed interface Shape permits Circle, Square { }
record Circle(double r) implements Shape { }
record Square(double side) implements Shape { }Nested classes
Java lets you declare a class inside another. There are four flavours:
- Static nested class — a helper grouped inside its outer class, but independent of any instance
- Inner class — non-static; tied to an instance of the outer class and can access its fields
- Local class — declared inside a method
- Anonymous class — a one-off class with no name, defined and instantiated at once
Anonymous classes are the most common — often used to implement an interface on the spot:
public class Main {
public static void main(String[] args) {
Runnable task = new Runnable() { // anonymous class
public void run() {
System.out.println("Running the task!");
}
};
task.run();
}
}Note
Runnable task = () -> System.out.println(...)) is a cleaner replacement for an anonymous class — which is exactly where we're headed in Module 17.Recap & quick check
Key takeaways
- An interface is a contract; a class can implement many (multiple inheritance of type).
- Default methods let interfaces ship real behaviour without breaking implementers.
- A functional interface has one abstract method and can be backed by a lambda.
- Enums model a fixed set of type-safe constants and can hold fields and methods.
- Records generate constructor/getters/equals/hashCode/toString for immutable data in one line.
Quick check
1. How many interfaces can a single class implement?
2. What defines a functional interface?
3. What does a record automatically generate?
4. When should you use an enum?
5. A default method in an interface…
Great progress — your OOP toolkit is now rich and modern. Next up: Module 11 — Packages, Access Control & Project Organization.