Skip to content
Java core 3 min read

Interfaces

An interface defines a contract: a set of methods a type promises to provide, without dictating how. Interfaces are Java’s primary tool for decoupling—callers depend on the interface, and any conforming implementation can be swapped in. Since Java 8 they have grown well beyond pure abstraction, gaining default and static methods.

Declaring and Implementing

An interface declares method signatures; a class adopts the contract with implements and supplies bodies.

public interface Repository<T> {
    void save(T entity);
    java.util.Optional<T> findById(long id);
}

public class InMemoryUserRepo implements Repository<String> {
    private final java.util.Map<Long, String> store = new java.util.HashMap<>();

    @Override public void save(String entity) { store.put((long) entity.hashCode(), entity); }
    @Override public java.util.Optional<String> findById(long id) {
        return java.util.Optional.ofNullable(store.get(id));
    }
}

Interface methods are implicitly public abstract; implementing methods must be public. Fields in an interface are implicitly public static final constants.

Default and Static Methods (Java 8)

A default method provides a body inside the interface, letting you add behavior without breaking existing implementors. A static method belongs to the interface itself and is called on its name.

public interface Greeter {
    String name();

    default String greet() {            // evolvable behavior
        return "Hello, " + name();
    }

    static Greeter of(String n) {       // factory on the interface
        return () -> n;
    }
}
Greeter g = Greeter.of("DevCraftly");
System.out.println(g.greet());

Output:

Hello, DevCraftly

Note: Default methods exist mainly to evolve published interfaces (the JDK used them to add Collection.stream() without breaking the ecosystem). Don’t overuse them to smuggle real logic into interfaces.

Functional Interfaces

A functional interface has exactly one abstract method, so it can be implemented by a lambda or method reference. Annotate it with @FunctionalInterface to have the compiler enforce that rule.

@FunctionalInterface
interface Transformer {
    String apply(String input);
}
Transformer upper = String::toUpperCase;
System.out.println(upper.apply("scale"));

Output:

SCALE

The java.util.function package ships ready-made functional interfaces—Function, Predicate, Supplier, Consumer—that power streams and lambdas throughout modern Java.

Multiple Interface Implementation

A class can implement any number of interfaces, composing capabilities that no single class hierarchy could.

public class Document implements Comparable<Document>, AutoCloseable {
    @Override public int compareTo(Document o) { return 0; }
    @Override public void close() { /* release resources */ }
}

If two interfaces supply default methods with the same signature, the compiler forces the implementing class to override the method and resolve the conflict explicitly—often delegating with Interface.super.method().

interface A { default String id() { return "A"; } }
interface B { default String id() { return "B"; } }

class C implements A, B {
    @Override public String id() { return A.super.id(); } // disambiguate
}

Warning: Without that explicit override, a default-method clash is a compile error. The language refuses to guess which one you meant.

Interface vs Abstract Class

AspectInterfaceAbstract Class
Multiple inheritanceYes (many)No (single)
Instance stateNo (constants only)Yes
ConstructorsNoYes
Method bodiesdefault/static/privateConcrete + abstract
ModelsA capability (can-do)An is-a with shared state
Lambda targetYes (if functional)No

Best Practices

  • Program to interfaces; declare variables and parameters by interface type.
  • Keep interfaces small and cohesive—prefer several focused contracts over one fat interface.
  • Use @FunctionalInterface to lock in single-abstract-method intent.
  • Reserve default methods for interface evolution, not for hiding substantial logic.
  • Reuse java.util.function types instead of inventing equivalents.

Interview Questions

Q: Can an interface have a constructor? A: No. Interfaces have no instance state to initialize, so they cannot declare constructors.

Q: How does Java resolve conflicting default methods from two interfaces? A: It doesn’t—the implementing class must override the method explicitly, optionally delegating with InterfaceName.super.method().

Q: What makes an interface a functional interface? A: Exactly one abstract method. Default, static, and Object-inherited methods don’t count, so the single abstract method can be supplied by a lambda or method reference.

Q: Since Java 8 added default methods, why still use abstract classes? A: Abstract classes can hold mutable instance state, declare constructors, and enforce a single shared base implementation—none of which interfaces support.

Last updated June 1, 2026
Was this helpful?