skip to content

How do static methods in an interface differ from default methods, and how are they invoked?

level: middleimportance: should knowfreq 55%

answer

  1. static = on the interface type, default = on the instance
  2. Call via Interface.method(...), never via an implementer
  3. Not inherited, not overridden, no dynamic dispatch
  4. Replaces the old companion-utility-class pattern
  5. Comparator.naturalOrder(), Stream.of(), List.of()

basics

~10 s

A static interface method belongs to the interface itself, not to any instance. You call it as Interface.method(...). Unlike a default method, it is not inherited by implementing classes and cannot be overridden.

solid answer

~40 s

Since Java 8 an interface can declare static methods with bodies. Like static methods on a class, they belong to the interface type, not to any instance, so you invoke them through the interface name (Comparator.naturalOrder(), Stream.of(...)). They are not inherited by implementing classes or sub-interfaces and cannot be overridden, so there's no polymorphism — the call is resolved statically. Their main purpose is to host interface-related helper or factory methods next to the interface itself, instead of in a separate companion utility class (the old MyTypeUtils pattern). A default method, by contrast, is an instance method inherited by every implementer and dynamically dispatched. So: default = inherited, overridable, called on an instance; static = owned by the interface, not inherited, called on the interface name.

code

java · 9 lines
java
interface Money {
    long cents();
    default String formatted() { return cents() / 100.0 + " USD"; }  // instance, inherited
    static Money ofDollars(long d) { return () -> d * 100; }          // type-level factory
}

Money m = Money.ofDollars(5);  // call static via the interface name
m.formatted();                 // call default on the instance
// Money impl = ...; impl.ofDollars(...)  // would NOT compile: not inherited

go deeper

for a junior

Knows you call a static interface method via the interface name and that it isn't tied to any object.

for a middle

Contrasts static (type-level, not inherited, no override, static dispatch) with default (instance-level, inherited, overridable, dynamic dispatch) and knows the factory/utility motivation.

for a senior

Explains how static interface methods replace the separate companion-utility-class pattern, cites JDK factories, and knows they aren't inherited by sub-interfaces either.

for a principal

Discusses API cohesion and discoverability trade-offs of co-locating factories on the interface, and how static plus private static methods let an interface encapsulate its own construction and helper logic without leaking a utility class.

## Two kinds of concrete interface method Java 8 gave interfaces two ways to carry a method body: **default methods** (instance methods) and **static methods** (type-level methods). They look similar but behave very differently. ### Static interface methods A **static method** in an interface is exactly like a static method on a class: it belongs to the **interface type itself**, not to any object. You declare it with `static` and a body: ```java interface Shape { double area(); static Shape unit() { // factory living on the interface return () -> 1.0; } } ``` You call it through the **interface name**: `Shape.unit()`. You **cannot** call it through an instance, and you **cannot** call it through an implementing class name either (`SomeShape.unit()` does not compile) — static interface methods are *not inherited*. Because they aren't inherited, they cannot be overridden, and there is **no dynamic dispatch**: the target is chosen at compile time from the type you named. ### Why they exist Before Java 8, helper and factory methods related to an interface had to live in a *separate companion class* — e.g. `java.util.Collections` holds helpers for `Collection`, `Arrays` for arrays. Static interface methods let those helpers live **on the interface itself**, keeping the API cohesive. Modern JDK examples: `Comparator.naturalOrder()`, `Comparator.comparing(...)`, `Stream.of(...)`, `List.of(...)`, `Map.entry(...)`, `Predicate.not(...)`. ### Side-by-side with default methods | Aspect | `default` method | `static` method | |---|---|---| | Belongs to | each **instance** | the **interface type** | | Invoked on | an object (`obj.m()`) | the interface (`Type.m()`) | | Inherited by implementers? | **Yes** | **No** | | Overridable? | **Yes** | **No** | | Dispatch | **dynamic** (runtime) | **static** (compile time) | | Typical use | evolve/extend behaviour all implementers share | factory/utility tied to the type | ### Subtle points - A static interface method is **not** inherited by a *sub-interface* either. If `B extends A` and `A` has `static foo()`, you still call `A.foo()`, not `B.foo()`. - A static method can be `private static` (see private interface methods) when it is only an internal helper for the interface's other methods. - Static and default methods can coexist; static methods often *implement* the factory while default methods provide shared instance behaviour.

  • Can a class that implements an interface inherit and call that interface's static method as if it were its own?
    No. Static interface methods are not inherited. You must call them through the interface name (Interface.method()), not through the implementing class or an instance.
  • Give a JDK example of a static interface method used as a factory.
    Comparator.naturalOrder(), Comparator.comparing(...), Stream.of(...), List.of(...), Map.entry(...), and Predicate.not(...) are all static interface methods, typically used as factories or helpers.

saying these in an interview costs you the question

  • Claiming static interface methods are inherited by implementing classes — they are not.
  • Saying static interface methods can be overridden — they cannot; there is no dynamic dispatch.
  • Confusing them with default methods, which are instance methods.
  • Thinking you call them via an instance reference.

context