🔌 Interfaces & Abstraction · Intermediate

Static & private interface methods in Java

Helpers in interfaces; static ones are not inherited by implementers.

🧩 The mysteryList.of(1, 2, 3) — wait, List is an interface. Since when can you call a method directly on an interface?

Utilities that live on the interface

Since Java 8, an interface can have static methods, called on the interface name: Iface.method(). Examples: List.of(...) (Java 9), Map.entry(...), Comparator.naturalOrder(). They're handy factories that sit right next to the type they create.

interface Ids {
    static String next() {
        return "ID-7";
    }
}
String id = Ids.next();
🔮 Predict it

Borrow through the class?

User implements Ids. What happens?

interface Ids {
    static String next() { return "ID-7"; }
}
class User implements Ids { }
void main() {
    System.out.println(User.next());
}
  1. ID-7
  2. Compile error
  3. null
Show the answer

Static interface methods are not inherited by implementing classes — not through the class name, not through an instance. Ids.next() works; User.next() doesn't compile.

Private helpers (Java 9)

Two defaults doing similar work? Since Java 9 an interface may have private methods to share that code. Here a() returns [a] and b() returns [b], both through wrap.

interface Fmt {
    default String a() { return wrap("a"); }
    default String b() { return wrap("b"); }
    private String wrap(String s) {
        return "[" + s + "]";
    }
}
⚠️ The trap

Implementers can't borrow private helpers

A private interface method is visible only inside the interface body. An implementing class that calls wrap() gets a compile error — private means private, even for the family.

class F implements Fmt {
    String test() {
        return wrap("x");   // error
    }
}

The full toolkit

An interface can now mix four kinds of methods: abstract — no body, implementers must provide one; default — has a body, inherited and overridable; static — called as Iface.m(), not inherited; private — a helper usable only inside the interface.

💼 In the real world

Factories on the type itself

Modern Java APIs lean on static interface methods: List.of, Map.of, Comparator.comparing, Path.of. Before Java 8, these had to live in separate helper classes like Collections and Paths, which made them harder to discover.

Key takeaways

  1. Call static interface methods as Iface.method()
  2. Static interface methods aren't inherited by implementers
  3. private methods are helpers visible only inside the interface
  4. Examples: List.of(), Map.entry(), Comparator.naturalOrder()
🤯 Did you know?

Paths.get() existed since Java 7 because interfaces couldn't hold static methods back then. Java 11 added Path.of() directly on the interface, and the JDK docs now recommend it instead.

Practice questions

What does this print?

interface Util {
    static String tag() { return "util"; }
}
class Impl implements Util { }
void main() {
    System.out.println(Impl.tag());
}
  1. util
  2. Compile error
  3. null
  4. Throws NoSuchMethodError
Check your answer

Compile error. Static interface methods belong only to the interface. Impl.tag() doesn't compile; Util.tag() would.

What does this print?

interface Fmt {
    default String a() { return wrap("a"); }
    default String b() { return wrap("b"); }
    private String wrap(String s) {
        return "[" + s + "]";
    }
}
class F implements Fmt { }
void main() {
    System.out.println(new F().a() + new F().b());
}
  1. [a][b]
  2. ab
  3. Compile error: private in interface
  4. [ab]
Check your answer

[a][b]. Since Java 9 interfaces may have private methods. Both defaults reuse wrap(), so the output is [a][b].

Next: interfaces can now hold real code… so why do abstract classes still exist? One word: state.