An interface declares a type that classes can implement, without fixing their state or their superclass. A class may implement any number of interfaces, and an interface may extend any number of others. Interfaces hold constants, abstract methods and, since Java 8 and 9, methods with bodies (JLS chapter 9).
Interface declarations
NormalInterfaceDeclaration:
{InterfaceModifier} interface TypeIdentifier [TypeParameters]
[extends InterfaceTypeList] [permits TypeName {, TypeName}] InterfaceBody
InterfaceModifier:
Annotation public protected private abstract static sealed non-sealed strictfp
InterfaceMemberDeclaration:
ConstantDeclaration | InterfaceMethodDeclaration | ClassDeclaration | InterfaceDeclaration | ;
- Every interface is implicitly
abstract; writing it is allowed but obsolete. An interface cannot befinal. - Member interfaces and local interfaces (Java 16) are implicitly
static. - An interface has no instance variables, constructors or initialisers.
- An interface does not extend
Object, but implicitly declares an abstract version of each public method ofObject, soequalsandtoStringcan be called on any interface type.
Members
public interface Shape extends Comparable<Shape> {
double UNIT = 1.0; // constant: public static final
double area(); // abstract: public abstract
default String describe() { // default method (Java 8)
return name() + " of area " + format(area());
}
default int compareTo(Shape other) {
return Double.compare(area(), other.area());
}
static Shape unitSquare() { // static method (Java 8)
return () -> UNIT;
}
private String name() { // private method (Java 9)
return getClass().getSimpleName();
}
private static String format(double d) { // private static method (Java 9)
return String.format("%.2f", d);
}
}
| Member | Implicit modifiers | Allowed modifiers | Since |
|---|---|---|---|
| Field (constant) | public static final | public, static, final | 1.0 |
| Abstract method | public abstract | public, abstract | 1.0 |
| Default method | public | public, default, strictfp | 8 |
| Static method | public unless private | public, private, static, strictfp | 8 (private: 9) |
| Private instance method | none | private, strictfp | 9 |
| Member class or interface | public static | public, static and the type’s own modifiers | 1.1 |
- Interface methods cannot be
protected,final,synchronizedornative. - A field must have an initialiser, which need not be a constant expression; it runs when the interface is initialised.
- A default method has a body and is inherited by implementing
classes, which may override it. It lets an interface gain methods without breaking
existing implementations. A default method may not have the signature of
equals,hashCodeortoString. - A static method belongs to the interface alone: it is not
inherited by implementing classes or subinterfaces and is called as
Shape.unitSquare(), never through an instance. - A private method has a body and is a helper for the other methods of the interface.
Inheriting default methods
When a class inherits several methods with the same signature, the compiler picks one by these rules (JLS 8.4.8, 9.4.1):
- Classes win. A method declared in the class or inherited from a superclass, even an abstract one, beats any default method from an interface.
- The more specific interface wins. If interface
BextendsAand both supply the method,B’s version is used. - Otherwise, if two unrelated interfaces both supply a default, or one supplies a
default and the other an abstract method, the class must override the method. It
may call either version with
Interface.super.method().
interface Walker { default String move() { return "walk"; } }
interface Swimmer { default String move() { return "swim"; } }
class Duck implements Walker, Swimmer {
@Override public String move() { // required: the two defaults conflict
return Walker.super.move() + " and " + Swimmer.super.move();
}
}
Functional interfaces
A functional interface has exactly one abstract method, not counting
methods that match public methods of Object (JLS 9.8). It may have any
number of default, static and private methods. Lambda expressions and method
references can only be written where a functional interface is expected; see
Lambdas.
@FunctionalInterface
interface Parser<T> {
T parse(String text) throws ParseException; // the single abstract method
boolean equals(Object o); // does not count: Object has it
default Parser<T> orElse(T fallback) {
return text -> {
try { return parse(text); } catch (ParseException e) { return fallback; }
};
}
}
The @FunctionalInterface annotation is optional; it makes the compiler
check the rule. Common functional interfaces in java.util.function and
elsewhere:
| Interface | Method | Function type |
|---|---|---|
Runnable | run | () -> void |
Callable<V> | call | () -> V, may throw Exception |
Supplier<T> | get | () -> T |
Consumer<T> | accept | T -> void |
Function<T, R> | apply | T -> R |
Predicate<T> | test | T -> boolean |
UnaryOperator<T> | apply | T -> T |
BiFunction<T, U, R> | apply | (T, U) -> R |
BinaryOperator<T> | apply | (T, T) -> T |
Comparator<T> | compare | (T, T) -> int |
IntFunction<R>, ToIntFunction<T>, IntPredicate … | various | Versions for primitive types, to avoid boxing |
Sealed interfaces
An interface can be sealed (Java 17), with a permits list
of the classes and interfaces that may directly extend or implement it. The rules are
the same as for sealed classes.
Records and enums are implicitly final (or, for an enum with constant bodies, sealed),
so they can implement sealed interfaces directly, which is the usual way to write an
algebraic data type:
sealed interface Expr permits Num, Add, Mul, Neg {}
record Num(int value) implements Expr {}
record Add(Expr left, Expr right) implements Expr {}
record Mul(Expr left, Expr right) implements Expr {}
record Neg(Expr operand) implements Expr {}
static int eval(Expr e) {
return switch (e) { // exhaustive: no default needed
case Num n -> n.value();
case Add(var l, var r) -> eval(l) + eval(r);
case Mul(var l, var r) -> eval(l) * eval(r);
case Neg(var x) -> -eval(x);
};
}