Skip to content
Lesson 14 of 15

Step 1 of 7 · Reading · ~3 min

Learn

Inheritance and Interfaces

Interfaces

An interface is a contract: a list of method signatures that any class promising to follow it must implement. By the end of this lesson you can define and implement an interface, give it a ready-made default method, and use a lambda wherever an interface has a single abstract method.

Defining and implementing

interface Check {
    boolean test(String s);       // no body: just the signature
}

static class NotEmpty implements Check {
    @Override
    public boolean test(String s) {
        return !s.isEmpty();
    }
}

static class MaxLen implements Check {
    private final int max;

    MaxLen(int max) {
        this.max = max;
    }

    @Override
    public boolean test(String s) {
        return s.length() <= max;
    }
}

A class that says implements Check must supply every method the interface declares, or the compiler refuses. Two details trip people up:

  • Interface methods are implicitly public, so the implementing method must be declared public too. Leaving it off gives "attempting to assign weaker access privileges".
  • The interface says what, never how. Different classes give different hows for the same what.

Code against the interface

The payoff comes when callers depend only on the interface:

Check[] rules = { new NotEmpty(), new MaxLen(5) };
for (Check rule : rules) {
    System.out.println(rule.test("abcdefg"));   // true, then false
}

The loop knows nothing about NotEmpty or MaxLen; it works for any class that implements Check, including ones written later. That is polymorphism through an interface, and it is how well-designed Java keeps parts replaceable and testable.

default methods

An interface can supply a method body marked default. Every implementor inherits it for free and may override it. A default method can call the interface's own abstract methods, because by then some real object is behind this:

interface Check {
    boolean test(String s);

    default Check and(Check other) {
        return s -> test(s) && other.test(s);
    }
}

and builds a new Check that passes only when both do. Now new NotEmpty().and(new MaxLen(5)) is itself a Check, and .and(...) chains again. Inside the lambda, test(s) is this object's check, and other.test(s) is the other one. Default methods exist so interfaces can grow without breaking classes that already implement them.

Lambdas: implementing an interface in one line

An interface with exactly one abstract method is a functional interface, and a lambda can stand in for a class that implements it:

Check noBang = s -> s.indexOf('!') < 0;
Check blank  = String::isEmpty;              // a method reference works too
System.out.println(noBang.test("hey!"));     // false

This is what powers streams: filter takes a Predicate, map takes a Function, and both are functional interfaces from java.util.function.

Static members, multiple interfaces

An interface may hold static helper methods and constants (fields are implicitly public static final). A class may implement several interfaces, class P implements Named, Aged, which is Java's answer to multiple inheritance: many contracts, one parent class. If two interfaces supply conflicting default methods, the class must override the method and choose.

Interface or abstract class?

Use an interface for a capability that unrelated classes can share. Use an abstract class when subclasses share state and partial implementation under one parent. Interfaces cannot hold per-object state.

Common mistakes

  • Implementing without public.
  • Leaving out a method the interface declares.
  • Calling a method through the interface type that exists only on the class. The variable's declared type decides what you may call.
  • Putting state in an interface; its fields are constants.

Your exercise

Text formatters share one contract, and the program composes a chain of them in the order they are named. You write the formatter classes and the default method that joins two formatters into one. Order matters: applying A then B is not the same as B then A.

Up nextException HandlingInheritance and Interfaces

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…