Nested Interface
A nested interface is an interface declared inside another class or interface. It’s a clean way to tie a contract directly to the type that owns it — think of the Map.Entry interface you use every time you iterate over a HashMap, or a Clickable.OnClickListener callback pattern you’ll recognize from GUI toolkits.
What Is a Nested Interface?
Just like you can nest a class inside another class, you can declare an interface inside a class or inside another interface. The syntax is exactly what you’d expect:
class Outer {
interface Printer {
void print(String message);
}
}
You then implement the nested interface using its fully qualified name: Outer.Printer.
class ConsolePrinter implements Outer.Printer {
@Override
public void print(String message) {
System.out.println(message);
}
}
public class Main {
public static void main(String[] args) {
Outer.Printer p = new ConsolePrinter();
p.print("Hello from a nested interface!");
}
}
Output:
Hello from a nested interface!
Note: Regardless of whether you declare a nested interface
public,protected, or with package-private access, the interface itself is always implicitlystatic. You do not need to write thestatickeyword — but you can. This means a nested interface never holds a reference to an enclosing instance, unlike a non-static member inner class.
Interface Nested Inside a Class
When you put an interface inside a class, you’re signalling: “this contract belongs to this class.” The most famous Java standard-library example is Map.Entry<K,V> from java.util.Map — it defines what a single key-value pair inside a Map looks like.
Here’s a realistic pattern — a Button class that defines its own listener contract:
class Button {
private String label;
public Button(String label) {
this.label = label;
}
// The callback contract lives right here, next to Button
public interface OnClickListener {
void onClick(Button source);
}
private OnClickListener listener;
public void setOnClickListener(OnClickListener listener) {
this.listener = listener;
}
public void click() {
System.out.println(label + " was clicked");
if (listener != null) {
listener.onClick(this);
}
}
public String getLabel() {
return label;
}
}
Now a caller can wire up the callback cleanly:
public class Main {
public static void main(String[] args) {
Button btn = new Button("Submit");
// Implement the nested interface inline (anonymous class)
btn.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(Button source) {
System.out.println("Handler: " + source.getLabel() + " clicked!");
}
});
btn.click();
}
}
Output:
Submit was clicked
Handler: Submit clicked!
Tip:
Button.OnClickListenerhas exactly one abstract method, so it is a functional interface. In Java 8+ you can replace the anonymous class with a lambda:btn.setOnClickListener(source -> System.out.println(source.getLabel() + " clicked!"));
Interface Nested Inside Another Interface
You can also declare an interface inside another interface. This is less common, but it’s how Java models hierarchical contracts — each sub-contract stays grouped with the parent that defines the domain.
interface Vehicle {
void start();
// Nested interface — a contract for an engine within any Vehicle
interface Engine {
void ignite();
int getHorsePower();
}
}
A class can implement either contract independently:
class Car implements Vehicle, Vehicle.Engine {
@Override
public void start() {
System.out.println("Car starting...");
}
@Override
public void ignite() {
System.out.println("Engine igniting");
}
@Override
public int getHorsePower() {
return 250;
}
}
public class Main {
public static void main(String[] args) {
Car car = new Car();
car.start();
car.ignite();
System.out.println("HP: " + car.getHorsePower());
}
}
Output:
Car starting...
Engine igniting
HP: 250
A nested interface inside another interface is implicitly public and static — the same rules as when nested inside a class.
Access Modifiers for Nested Interfaces
When a nested interface lives inside a class, it can carry any access modifier:
| Modifier | Visibility |
|---|---|
public | Accessible from anywhere |
protected | Accessible within same package + subclasses |
| (none) | Package-private — same package only |
private | Only the enclosing class can use it |
A private nested interface is handy when the contract is purely an internal implementation detail:
class DataProcessor {
// Hidden from the outside world
private interface Transformer {
String transform(String input);
}
private static class UpperCaseTransformer implements Transformer {
@Override
public String transform(String input) {
return input.toUpperCase();
}
}
public String process(String data) {
Transformer t = new UpperCaseTransformer();
return t.transform(data);
}
}
public class Main {
public static void main(String[] args) {
DataProcessor dp = new DataProcessor();
System.out.println(dp.process("hello"));
}
}
Output:
HELLO
When a nested interface lives inside another interface, it is always public — you cannot restrict it further.
Real-World Example: Map.Entry
The best-known nested interface in the Java standard library is Map.Entry<K,V>. It represents a single mapping inside a Map and is declared directly inside the Map interface. You use it whenever you iterate a HashMap:
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 87);
// Map.Entry is a nested interface inside Map
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
System.out.println(entry.getKey() + " -> " + entry.getValue());
}
}
}
Output:
Alice -> 95
Bob -> 87
Because Entry is declared inside Map, the qualified name makes the relationship unmistakable: an entry belongs to a map.
Under the Hood
Always Static at the Bytecode Level
The Java Language Specification mandates that every nested interface is implicitly static. The compiler enforces this: you cannot instantiate a nested interface as if it held an outer reference (the way a non-static inner class does). This means no hidden this$0 synthetic field is generated, so nested interfaces are lightweight at runtime.
You can verify this yourself with the javap tool: compile a class containing a nested interface and run javap -v Outer — the nested interface appears as a member with the ACC_STATIC and ACC_INTERFACE flags.
Separate .class Files
Like all nested types, the compiler produces a separate .class file for each nested interface. A nested interface Printer inside Outer produces:
Outer.class
Outer$Printer.class
The $ separator is a compiler convention. The JVM has no concept of “nesting” — it just loads two independent classes. The InnerClasses attribute in the bytecode records the nesting relationship so tools like IDEs and the reflection API can reconstruct it.
Implementing a Nested Interface Reflectively
Because nested interfaces are just regular interfaces at the JVM level, reflection treats them normally. You can call Button.OnClickListener.class.getName() and get "Button$OnClickListener", and Button.OnClickListener.class.getEnclosingClass() returns Button.class.
When to Use a Nested Interface
Use a nested interface when:
- The contract is tightly coupled to the enclosing type (callbacks, listeners, entry types).
- You want the qualified name to make the relationship self-documenting (
Map.Entry,Button.OnClickListener). - You need to hide an internal contract with
privateaccess.
Prefer a top-level interface when:
- Multiple unrelated classes will implement the contract.
- The interface is part of a public API that shouldn’t require knowing the enclosing class.
- The contract evolves independently of any single class.
Warning: Avoid deeply nesting interfaces (interface inside interface inside class) — it obscures your design and makes the qualified names unwieldy to read and type.
Related Topics
- Interfaces — the full guide to how interfaces work before nesting them.
- Inner Classes — overview of all four nested type kinds in Java.
- Static Nested Class — a class that, like a nested interface, carries no outer-instance reference.
- Anonymous Inner Class — the classic way to implement a nested interface inline without creating a named class.
- Functional Interfaces — single-method nested interfaces can be implemented with concise lambda expressions.
- Working of HashMap (Internals) — digs into
Map.Entry, the most famous nested interface in the JDK.