Interfaces

Reviewed & published by Brayan K

An interface is a contract: a list of methods a class promises to provide. Learn to declare and implement them, combine several at once, add default and static methods, and tell an interface from an abstract class.

Part of the free Java course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

What You'll Learn in This Lesson

📚 Before You Start

This lesson builds on classes and inheritance. Make sure you're comfortable with:

💡 The Big Idea — A Job Description

Analogy: An interface is a job description. It lists what the role must be able to do — "write reports, attend meetings, hit deadlines" — but it never says how. Two different people (classes) can both satisfy the same job description in completely different ways.

In code, the interface lists method names with no bodies. Any class that says implements the interface is signing the contract: it must supply a real version of every listed method. The payoff is that you can write one method that accepts the interface and it works with every class that implements it — present and future. That is what makes interfaces the backbone of flexible, testable Java.

1️⃣ Declaring and Implementing an Interface

You declare an interface with the interface keyword and list method signatures — a signature is just the return type, the name, and the parameters, with a semicolon instead of a body. These methods are automatically public and abstract, so you never write those words.

interface Drivable {
    String drive();      // no body — just the promise
    int getSpeed();
}

A class then implements the interface and provides a body for every method. Because the contract methods are public, your implementations must be public too.

class Car implements Drivable {
    private int speed = 0;
    public String drive()  { speed = 60; return "Driving"; }
    public int getSpeed()  { return speed; }
}
interface Drivable {
    // Interface methods are public + abstract by default — just a signature, no body.
    String drive();
    String stop();
    int getSpeed();
}

// "implements" = this class promises to provide EVERY method in the contract.
class Car implements Drivable {
    private int speed = 0;
    public String drive() { speed = 60; return "Car driving at " + speed + " mph"; }
    public String stop()  { speed = 0;  return "Car stopped"; }
    public int getSpeed() { return speed; }   // must be public — matches the contract
}

class Bicycle implements Drivable {
    private int speed = 0;
    public String drive() { speed = 15; return "Bicycle pedalling at " + speed + " mph"; }
    public String stop()  { speed = 0;  return "Bicycle stopped"; }
    public int getSpeed() { return speed; }
}

public class Main {
    // This method works with ANY Drivable — that is the whole point of an interface.
    static void testDrive(Drivable vehicle) {
        System.out.println(vehicle.drive());
        System.out.println("  Speed: " + vehicle.getSpeed() + " mph");
        System.out.println("  " + vehicle.stop());
    }

    public static void main(String[] args) {
        testDrive(new Car());        // pass a Car
        testDrive(new Bicycle());    // ...or a Bicycle — same method, no changes
    }
}

🎯 Your Turn #1 — Implement a Shape

The Square class promises to be a Shape, but two methods are blank. Fill in the ___ blanks so it satisfies the contract. Run it and check it against the expected output in the comment.

interface Shape {
    double area();          // 👉 you must give Square a body for this
    String name();
}

class Square implements Shape {
    private double side;
    Square(double side) { this.side = side; }

    // 🎯 YOUR TURN — finish the two methods this contract requires

    // 1) Return the area of the square (side * side)
    public double area() { return ___; }      // 👉 replace ___ with side * side

    // 2) Return the text "Square"
    public String name() { return ___; }      // 👉 replace ___ with "Square" in double quotes
}

public class Main {
    public static void main(String[] args) {
        Shape s = new Square(4);
        System.out.println(s.name() + " area = " + s.area());

        // ✅ Expected output: Square area = 16.0
    }
}

2️⃣ Multiple Interfaces

A class can only extends one parent class, but it can implements as many interfaces as you like — just separate them with commas. This is how Java gives you the flexibility of multiple inheritance without its headaches.

class Duck implements Flyable, Swimmable {
    public String fly()  { return "Flapping"; }
    public String swim() { return "Paddling"; }
}

A Duck now counts as a Flyable and a Swimmable. You can pass it to any method expecting either type. It just has to provide every method from every interface it signs up for.

3️⃣ Default, Static Methods, and Constants

Since Java 8 an interface can ship real behaviour, not just signatures:

interface Flyable {
    int MAX_ALTITUDE = 10000;                 // a constant (public static final)
    String fly();                             // abstract — must be implemented
    default String land() { return "Landing"; }   // inherited body
    static String info() { return "Has wings"; }   // called as Flyable.info()
}
interface Flyable {
    // CONSTANT: interface fields are implicitly public static final.
    int MAX_ALTITUDE = 10000;

    String fly();   // abstract — every Flyable must say how it flies

    // DEFAULT method: has a body, so implementers get it for free (Java 8+).
    default String land() { return "Landing safely below " + MAX_ALTITUDE + " ft"; }

    // STATIC method: belongs to the interface itself, called as Flyable.info().
    static String info() { return "Flyable: anything with wings or rotors"; }
}

interface Swimmable {
    String swim();
    default String dive() { return "Diving deep"; }
}

// A class can implement MANY interfaces (Java's answer to multiple inheritance).
class Duck implements Flyable, Swimmable {
    public String fly()  { return "Duck flapping its wings"; }
    public String swim() { return "Duck paddling along"; }
    // Inherits default land() and dive() for free — no need to write them.
}

public class Main {
    public static void main(String[] args) {
        Duck d = new Duck();
        System.out.println(d.fly());     // its own implementation
        System.out.println(d.land());    // default from Flyable
        System.out.println(d.swim());    // its own implementation
        System.out.println(d.dive());    // default from Swimmable
        System.out.println(Flyable.info());          // static, called on the interface
        System.out.println("Limit: " + Flyable.MAX_ALTITUDE);  // the constant
    }
}

🎯 Your Turn #2 — A Document That Prints and Saves

A Document should be both Printable and Saveable. Fill the blanks so it implements both interfaces and provides the missing method. Notice you get preview() for free from the default method.

interface Printable {
    String content();
    // A default method — you DON'T rewrite this, you just call it.
    default String preview() { return "Preview: " + content(); }
}

interface Saveable {
    String save();
}

// 🎯 YOUR TURN — a Document is both Printable AND Saveable

class Document implements ___, ___ {   // 👉 list both interfaces, separated by a comma
    private String text;
    Document(String text) { this.text = text; }

    // 1) Return the stored text
    public String content() { return text; }

    // 2) Return a save message
    public String save() { return ___; }   // 👉 replace ___ with "Saved!" in double quotes
}

public class Main {
    public static void main(String[] args) {
        Document doc = new Document("Hello");
        System.out.println(doc.preview());  // uses the default method for free
        System.out.println(doc.save());

        // ✅ Expected output:
        // Preview: Hello
        // Saved!
    }
}

4️⃣ Interface Inheritance & Functional Interfaces

Interfaces can extends other interfaces to build bigger contracts. A class that implements the child must satisfy the whole chain — every method, inherited or added.

interface Animal { String name(); }
interface Pet extends Animal { String owner(); }   // Pet = name() + owner()

class Dog implements Pet {
    public String name()  { return "Rex"; }    // from Animal
    public String owner() { return "Sam"; }    // from Pet
}

When an interface has exactly one abstract method, it's a functional interface, and you can implement it with a one-line lambda instead of a whole class. Mark it with @FunctionalInterface and the compiler checks there's only one abstract method.

@FunctionalInterface
interface Greeter { String greet(String who); }

Greeter g = who -> "Hello, " + who + "!";   // the lambda IS the method body
System.out.println(g.greet("Ada"));          // Hello, Ada!
// Interfaces can extend OTHER interfaces (and even several at once).
interface Animal {
    String name();
}

interface Pet extends Animal {     // Pet inherits name() and adds owner()
    String owner();
}

class Dog implements Pet {
    // Must implement BOTH name() (inherited) and owner() (added) — the full chain.
    public String name()  { return "Rex"; }
    public String owner() { return "Sam"; }
}

// A FUNCTIONAL interface has exactly one abstract method, so a lambda can fill it.
@FunctionalInterface
interface Greeter {
    String greet(String who);      // the single abstract method
}

public class Main {
    public static void main(String[] args) {
        Pet p = new Dog();
        System.out.println(p.name() + " is owned by " + p.owner());

        // A lambda IS the implementation of the single method.
        Greeter g = who -> "Hello, " + who + "!";
        System.out.println(g.greet("Ada"));
    }
}

5️⃣ Interface vs Abstract Class

Both let you define methods a subclass must implement, so when do you reach for which? An abstract class is a partial class: it can hold normal fields, a constructor, and finished methods, but a class can extends only one. An interface is a pure contract a class can implement many of.

Analogy: an abstract class is a half-built house — the foundations and framing are already poured (shared code and state), you just finish the rooms. An interface is the building code — a list of requirements any house must meet, but it builds nothing itself.

Common Errors (and the Fix)

📋 Quick Reference — Interface vs Abstract Class

FeatureInterfaceAbstract Class
Keyword to use itimplementsextends
How many at onceMany (implements A, B)One only
MethodsAbstract + default + staticAbstract + concrete
FieldsConstants only (public static final)Any fields, incl. mutable state
Constructor❌ None✅ Yes
Can be instantiated?❌ No❌ No
Best forUnrelated classes sharing a capabilityRelated classes sharing code + state

🏆 Mini-Challenge — Build a Notifier

Time to write it from scratch. The starter below is just an outline of comments — design the interface and two implementing classes yourself, then loop over them polymorphically. Check your result against the expected output.

public class Main {
    // 🎯 MINI-CHALLENGE: a notifier contract
    //
    // 1. Declare an interface "Notifier" with one method: String send(String message)
    // 2. Make a class "EmailNotifier" that implements Notifier
    //      - send() returns: "Email: " + message
    // 3. Make a class "SmsNotifier" that implements Notifier
    //      - send() returns: "SMS: " + message
    // 4. In main, make a Notifier[] holding one of each, loop over it,
    //    and print send("Hi") for each.
    //
    // ✅ Expected output:
    // Email: Hi
    // SMS: Hi

    public static void main(String[] args) {
        // your code here
    }
}

🎉 Lesson Complete!

Great work! You can now declare an interface, implement it (even several at once), add default and static methods and constants, use a functional interface with a lambda, build contracts through interface inheritance, and pick an interface or an abstract class with confidence. These are the tools every Java framework — Spring, Android, Jakarta — is built on.

Practice quiz

Which keyword does a class use to provide an interface's methods?

  • extends
  • inherits
  • implements
  • uses

Answer: implements. A class uses 'implements' to fulfil an interface contract.

By default, interface methods (without a body) are implicitly...

  • public and abstract
  • private and static
  • protected and final
  • package-private

Answer: public and abstract. Interface abstract methods are implicitly public and abstract.

How many interfaces can a single class implement?

  • Exactly one
  • At most two
  • None
  • As many as you like

Answer: As many as you like. A class can implement many interfaces, separated by commas.

What kind of interface method has a body and is inherited for free by implementers?

  • abstract
  • default
  • private
  • final

Answer: default. A 'default' method (Java 8+) provides a body every implementer inherits.

A field declared in an interface like 'int MAX = 10000;' is implicitly...

  • public static final
  • private final
  • protected static
  • volatile

Answer: public static final. Interface fields are implicitly public static final — constants.

How do you call a static interface method named info() on interface Flyable?

  • new Flyable().info()
  • this.info()
  • Flyable.info()
  • super.info()

Answer: Flyable.info(). Static interface methods are called on the interface name: Flyable.info().

What is a functional interface?

  • An interface with no methods
  • An interface with exactly one abstract method
  • An interface that extends a class
  • An interface with only static methods

Answer: An interface with exactly one abstract method. A functional interface has exactly one abstract method, so a lambda can implement it.

Why must a class's implementations of interface methods be declared public?

  • For speed
  • Because of generics
  • To enable inheritance
  • Interface methods are public, and you cannot assign weaker access

Answer: Interface methods are public, and you cannot assign weaker access. You cannot give weaker access than the interface's public methods, so implementations must be public.

Can an interface extend another interface?

  • No, never
  • Yes, even several at once
  • Only abstract classes
  • Only if it is functional

Answer: Yes, even several at once. Interfaces can extend other interfaces to build larger contracts.

When should you prefer an abstract class over an interface?

  • Always
  • When you need multiple inheritance
  • When you need shared mutable state (fields) or a constructor
  • When you only have constants

Answer: When you need shared mutable state (fields) or a constructor. Start with an interface; switch to an abstract class when you need shared state or a constructor.

Continue this course

Frequently asked questions

What is the difference between an interface and an abstract class?

An interface is a pure contract: it lists method signatures (plus optional default/static methods and constants) and a class can implement many of them. An abstract class is a partial blueprint that can hold normal fields, constructors, and concrete methods, but a class can extend only one. Rule of thumb: start with an interface, and switch to an abstract class only when you need shared mutable state (fields) or a constructor.

Can an interface have method bodies?

Yes, since Java 8. A default method provides a body that every implementing class inherits unless it overrides it, and a static method belongs to the interface itself and is called like Flyable.info(). Java 9 also added private interface methods for sharing logic between default methods. The plain abstract methods still have no body — they are the contract each class must fulfil.

Why does my class fail to compile when I implement an interface?

The two usual causes are: you did not provide a body for every abstract method in the interface (and every interface it extends), or you implemented a method without the public modifier. Interface methods are implicitly public, and Java will not let you implement them with weaker access, so each one must be declared public in your class.

What is a functional interface and why does it matter?

A functional interface has exactly one abstract method, which lets you supply its implementation with a lambda expression instead of a whole class. Standard examples include Runnable, Comparator, and the java.util.function types like Function and Predicate. The optional @FunctionalInterface annotation makes the compiler check that the interface really has just one abstract method.

How does Java handle the diamond problem with default methods?

If a class implements two interfaces that both provide a default method with the same signature, the code will not compile until you resolve the clash. You override the method in your class and, if you want one of the originals, call it explicitly with InterfaceName.super.methodName(). This forces an intentional choice rather than letting Java guess.

Related lessons