Interfaces
BeginnerDefine contracts with interfaces, implement multiple interfaces, add default/static methods (Java 8+), and understand functional interfaces.
Overview
An interface defines a contract — a set of method signatures a class promises to implement. Interfaces enable multiple type inheritance (a class can implement many interfaces), loose coupling, and testability. Java 8 enriched interfaces with default methods (provide an implementation in the interface itself) and static methods. Java 9 added private methods. A functional interface has exactly one abstract method and is the target type for lambda expressions.
Defining & Implementing Interfaces
All interface methods are implicitly public and abstract unless marked default, static, or private. All interface fields are implicitly public, static, and final (constants). A class uses implements to adopt an interface and must provide implementations for all abstract methods — or declare itself abstract.
A class can implement multiple interfaces, solving the multiple-inheritance problem. If two interfaces define the same default method, the implementing class must override it to resolve the conflict.
public interface Drawable {
// Abstract method — must be implemented
void draw();
// Constant (public static final implicitly)
int MAX_SIZE = 1000;
}
public interface Resizable {
void resize(double factor);
}
// Implementing multiple interfaces
public class Circle implements Drawable, Resizable {
private double radius;
public Circle(double radius) { this.radius = radius; }
@Override
public void draw() {
System.out.println("Drawing circle with radius " + radius);
}
@Override
public void resize(double factor) {
radius *= factor;
System.out.println("Resized to radius " + radius);
}
public static void main(String[] args) {
Circle c = new Circle(5.0);
c.draw(); // Drawing circle with radius 5.0
c.resize(2.0); // Resized to radius 10.0
// Polymorphic — interface reference
Drawable d = new Circle(3.0);
d.draw();
// d.resize(2.0); // compile error — Drawable doesn't have resize
}
}Default, Static & Private Methods (Java 8+)
Default methods let you add new methods to an interface without breaking all existing implementations — crucial for evolving APIs like the Java Collections Framework (Iterable.forEach was added as a default method in Java 8).
Static interface methods belong to the interface itself, not to instances. They are utility methods related to the interface's contract.
Private interface methods (Java 9+) allow code reuse between default methods without exposing the helper to implementing classes.
import java.util.List;
public interface Validator<T> {
// Abstract — must implement
boolean isValid(T value);
// Default — optional override; adds behaviour without breaking existing code
default T validatedOrThrow(T value) {
if (!isValid(value)) {
throw new IllegalArgumentException("Invalid value: " + value);
}
return value;
}
// Default using private helper
default String status(T value) {
return isValid(value) ? formatOk(value) : formatFail(value);
}
// Private helper (Java 9+) — not visible to implementing classes
private String formatOk(T value) { return "OK: " + value; }
private String formatFail(T value) { return "FAIL: " + value; }
// Static utility — belongs to the interface, not instances
static <T> Validator<T> of(java.util.function.Predicate<T> predicate) {
return predicate::test; // lambda implementing Validator
}
}
// Minimal implementation — only overrides isValid()
class PositiveValidator implements Validator<Integer> {
@Override
public boolean isValid(Integer value) { return value != null && value > 0; }
public static void main(String[] args) {
PositiveValidator v = new PositiveValidator();
System.out.println(v.status(5)); // OK: 5
System.out.println(v.status(-3)); // FAIL: -3
Validator<String> notEmpty = Validator.of(s -> !s.isBlank());
System.out.println(notEmpty.status("hello")); // OK: hello
}
}Interface vs Abstract Class & Functional Interfaces
When to use interface vs abstract class:
Use interface when: defining a capability/contract that unrelated classes share (Comparable, Serializable, Runnable), multiple inheritance of type is needed, or the implementor is not in your control.
Use abstract class when: sharing code (not just a contract) among related classes, you need constructors or non-final/non-static fields, or you want to enforce a template method pattern.
A functional interface has exactly one abstract method (SAM — Single Abstract Method). Annotate with @FunctionalInterface so the compiler enforces this. Lambda expressions and method references can be assigned to any functional interface variable.
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
// @FunctionalInterface — compiler error if more than 1 abstract method
@FunctionalInterface
interface Transformer<T, R> {
R transform(T input);
// Default methods don't count toward the SAM count
default Transformer<T, R> andLog() {
return input -> {
R result = this.transform(input);
System.out.println(input + " → " + result);
return result;
};
}
}
public class FunctionalDemo {
public static void main(String[] args) {
// Lambda assigned to functional interface
Transformer<String, Integer> length = String::length; // method ref
// Predicate is a built-in functional interface
Predicate<String> isLong = s -> s.length() > 5;
List<String> words = List.of("Java", "interfaces", "rocks");
words.stream()
.filter(isLong)
.map(length.andLog())
.forEach(n -> {});
// Common built-in functional interfaces
// Runnable — () → void
// Supplier<T> — () → T
// Consumer<T> — T → void
// Function<T,R> — T → R
// Predicate<T> — T → boolean
// BiFunction<T,U,R>— T,U → R
}
}Interactive Visualization
Key Points to Remember
- Interface methods are public+abstract by default; fields are public+static+final
- A class can implement multiple interfaces — Java's answer to multiple inheritance
- Default methods (Java 8+) add behaviour to interfaces without breaking existing implementations
- If two interfaces have the same default method, the implementing class must override it
- A functional interface has exactly one abstract method — use @FunctionalInterface to enforce this
- Prefer interfaces for defining contracts and capabilities; use abstract classes when sharing code
Practice Interfaces in the Playground
Run and modify code directly in your browser - no setup needed.
Interview Questions
Sign in to ask AriaWhat is the difference between an interface and an abstract class?
Can an interface have a constructor in Java?
What are default methods in interfaces? Why were they added in Java 8?
What is a functional interface? Give three examples from the JDK.
What happens when a class implements two interfaces that both have the same default method?
Ask Aria about Interfaces
Your personal AI tutor — ask anything about this concept