Home/Learn/Java A–Z/Interfaces

Interfaces

Beginner
Java Fundamentals

Define 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.

Circle.java
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.

Validator.java
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.

FunctionalDemo.java
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

C = ClassA = AbstractI = Interface
CObject
Object is the root of the Java class hierarchy. Every class extends Object.
1 / 5

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 Aria
1

What is the difference between an interface and an abstract class?

MediumAmazon
2

Can an interface have a constructor in Java?

EasyTCS
3

What are default methods in interfaces? Why were they added in Java 8?

MediumOracle
4

What is a functional interface? Give three examples from the JDK.

MediumGoogle
5

What happens when a class implements two interfaces that both have the same default method?

MediumMicrosoft

Ask Aria about Interfaces

Your personal AI tutor — ask anything about this concept