00:00

Nested Interface in Java – Interfaces Inside Classes and Interfaces

A nested interface (also called an inner interface) is an interface declared inside a class or another interface. It groups an interface with the type it belongs to, so the relationship is obvious from the name, as in Map.Entry or Button.ClickListener.

This tutorial covers nested interfaces inside classes and inside interfaces, their implicit modifiers and access rules, and when to use them.

1. What Is a Nested Interface?

Syntax
class Outer {
    interface Inner { ... }        // nested in a class: any access modifier allowed
}

interface OuterInterface {
    interface Inner { ... }        // nested in an interface: always public static
}

class Impl implements Outer.Inner { ... }   // refer to it as Outer.Inner

Nested interfaces are always implicitly static: they do not belong to an instance of the outer type, so there is no "inner interface object" tied to an outer object.

2. Nested Interface Inside a Class

A common use is a callback type that belongs to a component, like a click listener of a button:

NestedInClass.java
public class NestedInClass {
    static class Button {
        // Nested interface: belongs logically to Button (implicitly static)
        public interface ClickListener {
            void onClick(String buttonLabel);
        }

        private final String label;
        private ClickListener listener;

        Button(String label) { this.label = label; }
        void setOnClickListener(ClickListener listener) { this.listener = listener; }
        void click() { if (listener != null) listener.onClick(label); }
    }

    // A class implementing the nested interface uses Outer.Inner as the name
    static class Logger implements Button.ClickListener {
        public void onClick(String buttonLabel) { System.out.println("LOG: '" + buttonLabel + "' clicked"); }
    }

    public static void main(String[] args) {
        Button save = new Button("Save");
        save.setOnClickListener(new Logger());
        save.click();

        Button cancel = new Button("Cancel");
        cancel.setOnClickListener(label -> System.out.println("Lambda: " + label + " pressed"));
        cancel.click();
    }
}
Output
LOG: 'Save' clicked
Lambda: Cancel pressed

The name Button.ClickListener clearly says "the listener type for buttons". Because it has a single abstract method, it is also a functional interface and accepts a lambda.

3. Nested Interface Inside an Interface

An interface can define a related interface, such as the entry type of a container. The JDK's Map.Entry is the best-known example:

NestedInInterface.java
import java.util.Map;
import java.util.TreeMap;

public class NestedInInterface {
    interface Cache {
        // Nested interface inside an interface: implicitly public static
        interface Entry {
            String key();
            int hits();
        }
        void put(String key);
        Iterable<? extends Entry> entries();
    }

    static class SimpleCache implements Cache {
        record Item(String key, int hits) implements Cache.Entry { }
        private final Map<String, Integer> data = new TreeMap<>();
        public void put(String key) { data.merge(key, 1, Integer::sum); }
        public Iterable<Item> entries() {
            return data.entrySet().stream().map(e -> new Item(e.getKey(), e.getValue())).toList();
        }
    }

    public static void main(String[] args) {
        Cache cache = new SimpleCache();
        for (String k : new String[] {"java", "spring", "java", "kafka", "java"}) cache.put(k);
        for (Cache.Entry e : cache.entries()) System.out.println(e.key() + " -> " + e.hits());

        // The JDK's best-known nested interface: Map.Entry
        Map<String, Integer> scores = Map.of("Asha", 91);
        for (Map.Entry<String, Integer> e : scores.entrySet())
            System.out.println("Map.Entry: " + e.getKey() + "=" + e.getValue());
    }
}
Output
java -> 3
kafka -> 1
spring -> 1
Map.Entry: Asha=91

4. Rules and Modifiers

Declared insideAllowed access modifiersImplicit modifiers
A classpublic, protected, package-private, privatestatic
An interfacepublic onlypublic static
  • A nested interface is referenced as Outer.Inner, or imported directly (import java.util.Map.Entry;).
  • Implementing the outer class or interface does not require implementing its nested interface, and vice versa.
  • A private nested interface can be implemented only within the outer class, which is useful for internal strategies.
  • Since Java 16, interfaces (and records and enums) can also be declared as local types inside a method body.

5. Nested Interfaces in the JDK

  • Map.Entry<K, V>: a key-value pair in a map.
  • Thread.UncaughtExceptionHandler: handles exceptions that end a thread.
  • Thread.Builder (Java 21): builds platform and virtual threads.
  • java.net.http.HttpResponse.BodyHandler: decides how to process an HTTP response body.

6. When to Use Nested Interfaces

  • The interface only makes sense together with the outer type (callbacks, entries, handlers).
  • You want to keep the package namespace clean and the relationship explicit.
  • You want to restrict visibility, for example a private interface used only inside one class.

If the interface is useful on its own, in many unrelated places, a top-level interface is clearer.

7. Summary

  • A nested interface is declared inside a class or interface and referred to as Outer.Inner.
  • Nested interfaces are implicitly static.
  • Inside an interface they are always public; inside a class they can have any access level.
  • They group closely related types, as in Map.Entry and listener interfaces.

Related Tutorials