Skip to content
Chapter 15 · Core Java

Interfaces In Depth ​

Java interfaces are one of those topics where you might think you already know enough, then realize how much depth is hiding beneath the surface. This article goes through everything you need to deeply understand interfaces: what they are, why they exist, how they behave, and every interview question worth knowing.


What an Interface Actually Is ​

Think about two systems that need to talk to each other. System 2 does a lot of complex work internally. System 1 wants to use System 2's capabilities but has no interest in how System 2 achieves anything internally. So System 2 publishes a short menu of operations: "here are the things you can ask me to do." System 1 reads that menu, makes requests, and lets System 2 handle everything behind the scenes. That menu is the interface.

The key insight here is that System 1 does not need to know how System 2 does anything. The internal complexity of System 2 is completely hidden. All System 1 ever sees is the list of operations it is allowed to call.

A real world example that makes this concrete: think about driving a car. When you press the brake pedal, you are interacting with an interface. The brake pedal is the operation exposed to you. You press it, and the car slows down. You have zero knowledge of whether the car uses disc brakes, drum brakes, hydraulic pressure, regenerative braking, or some combination of all of those. All of that complexity is hidden from you. The pedal is the contract between you and the car.

In Java terms: the car is a class that implements the interface. The brake pedal is a method signature on that interface. You are the system calling that method. You never need to look inside the class.

One sentence summary of what an interface does: an interface defines what a class must do but not how it does it.


How to Declare an Interface ​

The syntax for an interface is straightforward:

java
// Basic interface declaration
public interface Bird {
    void fly();   // implicitly: public abstract void fly()
    void eat();   // also implicitly public abstract
}

An interface declaration has four parts: the access modifier, the interface keyword, the interface name, and the body.

For the access modifier, only two options exist at the top level: public and default (no modifier, which means package private). You cannot declare a top level interface as protected or private. This is different from a class modifier inside another class, but for a standalone top level interface, it is public or nothing.

An interface can also extend other interfaces. Notice the word "extend," not "implement." An interface extends other interfaces:

java
// An interface that extends multiple parent interfaces
interface NonFlyingBird extends Bird, LivingThing {
    boolean canRun();
}

One important rule: after the extends keyword in an interface, you can only list other interface names. You cannot extend a class from inside an interface definition. If you try, the compiler rejects it immediately.


Why Interfaces Exist: Three Reasons ​

There are three core reasons Java has interfaces. Interviewers ask about all three. You should be able to explain all three with examples.

Reason One: Achieving Full Abstraction ​

An interface gives you a way to expose behavior without exposing implementation. Every method inside an interface is just a signature with no body. The implementing class provides the how. The caller only ever sees the what.

Before Java 8, this was absolute: every single method in an interface was abstract with no implementation whatsoever. Java 8 added default and static methods, and Java 9 added private methods. But the core promise of an interface remains: it tells you what a class will do, not how.

This is why interfaces are said to achieve "100% abstraction" (in the pre Java 8 sense). No concrete implementation leaks through.

Reason Two: Polymorphism Through Interface References ​

An interface can act as a data type. You can declare a variable whose type is an interface, and that variable can hold any object whose class implements that interface.

java
interface Bird {
    void fly();
}

class Eagle implements Bird {
    @Override
    public void fly() {
        System.out.println("Eagle soars high above the clouds");
    }
}

class Hen implements Bird {
    @Override
    public void fly() {
        System.out.println("Hen flutters a few feet off the ground");
    }
}

// Interface used as a data type
Bird b1 = new Eagle();   // b1 holds an Eagle object
Bird b2 = new Hen();     // b2 holds a Hen object

b1.fly();   // prints: Eagle soars high above the clouds
b2.fly();   // prints: Hen flutters a few feet off the ground

// Bird b = new Bird();   // COMPILE ERROR: you cannot instantiate an interface

Here is what happens at runtime when you call b1.fly(). The JVM looks at what actual object b1 is holding. It finds an Eagle object. It then calls Eagle's version of fly(). When you call b2.fly(), the JVM performs the same lookup, finds a Hen, and calls Hen's version of fly().

This runtime decision about which method to invoke is dynamic polymorphism. The same method call resolves differently depending on what object the interface reference actually contains. The compiler does not decide which implementation runs; the JVM decides at runtime.

One thing to remember permanently: you can never create an object of an interface directly. You cannot write new Bird(). An interface has no implementation, so there is nothing for the JVM to construct. You create objects of concrete classes and hold references to them through an interface variable.

Reason Three: Multiple Inheritance Without the Diamond Problem ​

Java does not allow a class to extend more than one class. This restriction exists because of the diamond problem. Imagine two parent classes, both with a method called canBreathe(). A child class tries to inherit from both. When you call child.canBreathe(), the compiler has no idea which version to use. There is no safe answer. This ambiguity is the diamond problem.

java
// This does NOT compile in Java
// class Crocodile extends WaterAnimal, LandAnimal { }
// Compiler cannot resolve which canBreathe() to use

Interfaces solve this cleanly. When you implement multiple interfaces that both declare the same method, the class is forced to write its own implementation. One implementation. Zero ambiguity:

java
interface WaterAnimal {
    boolean canBreathe();   // just a signature, no body
}

interface LandAnimal {
    boolean canBreathe();   // just a signature, no body
}

// This works perfectly
class Crocodile implements WaterAnimal, LandAnimal {
    @Override
    public boolean canBreathe() {   // one implementation, no confusion
        return true;
    }
}

Crocodile c = new Crocodile();
c.canBreathe();   // unambiguous: Crocodile's own implementation runs

Because interface methods have no body, there is nothing to conflict. The class provides the one and only implementation. The compiler is satisfied. This is exactly why multiple inheritance is possible through interfaces in Java but not through classes.


Methods in Interfaces: What the Compiler Adds for You ​

When you write a method inside an interface, you write less than what Java actually sees. The compiler silently adds keywords that you did not type.

java
public interface Bird {
    void fly();          // you write this
    // Java actually sees: public abstract void fly();

    public void eat();   // you write this
    // Java actually sees: public abstract void eat();
    // Both forms are identical; both compile fine
}

Every method in an interface is implicitly public. You can write the word public explicitly if you want, but it makes no difference. Whether you write it or omit it, the method is public.

Every method in an interface is implicitly abstract. Again, you can write the word abstract explicitly, but it changes nothing. The method is always abstract.

There is one access modifier you will never use on an interface method: final. Here is why. final on a method means "this method cannot be overridden in any subclass." But the entire purpose of an interface method is to be overridden (implemented) by the class that uses it. Putting final on an interface method is a direct contradiction of the interface's purpose. The compiler forbids it.

You also cannot use protected or private on interface methods (in standard Java before Java 9). Everything in an interface is public. The interface is designed to be a public contract between systems.


Fields in Interfaces: Why They Are Always Constants ​

Variables declared in an interface are treated differently from variables in a class. Every field in an interface is implicitly public static final.

java
public interface FlightConstants {
    int MAX_HEIGHT_IN_FEET = 2000;
    // Java actually sees: public static final int MAX_HEIGHT_IN_FEET = 2000;

    public static final int MIN_HEIGHT_IN_FEET = 100;
    // Same as above: both declarations are identical
}

public means you can access it from anywhere. static means it belongs to the interface itself rather than to any instance. final means once you set the value, you cannot change it. Combined, public static final makes every interface field a constant.

This makes sense when you think about what an interface is. An interface represents a contract, not a thing with state. State implies mutable values that differ from object to object. An interface cannot be instantiated, so there are no "instances" to hold varying state. Constants are appropriate: fixed values shared by everyone who uses the interface.

If you try to make an interface field private or protected, the compiler rejects it. Fields in an interface are always public. If you try to reassign a field after it is declared, the compiler rejects that too, because it is final.


Implementing an Interface: The Rules ​

A Concrete Class Must Implement Everything ​

When a regular (concrete) class declares implements SomeInterface, it must provide a complete method body for every single method declared in that interface. No exceptions. If even one method is missing a body, the compiler gives an error.

java
interface Bird {
    void fly();
    void eat();
    int numberOfLegs();
}

class Eagle implements Bird {
    @Override
    public void fly() {
        System.out.println("Eagle flies");
    }

    @Override
    public void eat() {
        System.out.println("Eagle eats fish");
    }

    @Override
    public int numberOfLegs() {
        return 2;
    }
    // All three methods implemented: compiles fine
}

You Cannot Reduce Visibility ​

The interface declares a method as public (even if you did not write the word public, the compiler added it). Your implementing class must honor that. You cannot make the method protected or private in the implementing class. That would be reducing the visibility, which is forbidden.

java
interface Bird {
    void fly();   // implicitly public
}

class Parrot implements Bird {
    // protected void fly() { }   // COMPILE ERROR: more restrictive than public
    public void fly() { }          // correct: same visibility as the interface
}

This rule applies to all inheritance in Java, not just interfaces. A subclass cannot reduce the visibility of an overridden method.

An Abstract Class Can Implement Partially ​

An abstract class that implements an interface does not have to provide implementations for every method. Because it is abstract, it can leave some methods unimplemented. However, the first concrete class in the inheritance chain must provide implementations for all remaining abstract methods.

java
interface Bird {
    boolean canFly();
    int numberOfLegs();
}

// Abstract class implements the interface but only partially
abstract class Eagle implements Bird {
    @Override
    public boolean canFly() {
        return true;   // implemented
    }
    // numberOfLegs() is NOT implemented here; that is allowed because Eagle is abstract

    // An abstract class can also add its own new abstract methods
    abstract int beakLength();
}

// Concrete class must finish EVERYTHING left abstract
class WhiteEagle extends Eagle {
    @Override
    public int numberOfLegs() {
        return 2;   // finishing what Eagle left abstract from Bird
    }

    @Override
    public int beakLength() {
        return 5;   // finishing Eagle's own abstract method
    }
}

The concrete class WhiteEagle walks up the entire inheritance chain and finds every abstract method that still needs a body. It provides bodies for all of them.

A Class Can Implement Multiple Interfaces ​

Java allows a single class to implement as many interfaces as you need, separated by commas:

java
interface Swimmer {
    void swim();
}

interface Runner {
    void run();
}

interface Flyer {
    void fly();
}

// One class implements three interfaces
class Duck implements Swimmer, Runner, Flyer {
    @Override
    public void swim() { System.out.println("Duck paddles"); }

    @Override
    public void run() { System.out.println("Duck waddles"); }

    @Override
    public void fly() { System.out.println("Duck flaps wings"); }
}

This is multiple inheritance of behavior through interfaces. It is perfectly legal and the main reason Java chose interfaces as the mechanism for multiple inheritance.


Nested Interfaces ​

Java allows you to declare an interface inside another interface, or inside a class. These are called nested interfaces.

Interface Inside an Interface ​

When you nest an interface inside another interface, the nested interface must be public. This follows the general rule that everything inside an interface is public:

java
public interface Bird {
    boolean canFly();   // outer interface method

    // nested interface: must be public
    public interface NonFlyingBird {
        boolean canRun();   // inner interface method
    }
}

A class can choose to implement just the outer interface, just the inner interface, or both. These are independent choices:

java
// Implementing only the outer interface
class Eagle implements Bird {
    @Override
    public boolean canFly() {
        return true;
    }
    // canRun() not required here; Eagle only implements Bird, not Bird.NonFlyingBird
}

// Implementing only the inner interface
class Ostrich implements Bird.NonFlyingBird {
    @Override
    public boolean canRun() {
        return true;
    }
    // canFly() not required here; Ostrich only implements Bird.NonFlyingBird
}

// Implementing both
class Penguin implements Bird, Bird.NonFlyingBird {
    @Override
    public boolean canFly() {
        return false;
    }

    @Override
    public boolean canRun() {
        return true;
    }
}

You access the inner interface using dot notation: Bird.NonFlyingBird. You can also use the inner interface as a reference type:

java
// Inner interface used as a reference variable type
Bird.NonFlyingBird ref = new Ostrich();
ref.canRun();   // JVM looks up actual object type (Ostrich), calls Ostrich's canRun()

Interface Inside a Class ​

When you nest an interface inside a class, the access modifier rules relax. A nested interface inside a class can be public, protected, private, or default. It follows the same rules as any other class member:

java
public class Bird {
    // nested interface inside a class: can be protected
    protected interface NonFlyingBird {
        boolean canRun();
    }
}

// Implementing the interface nested inside a class
class Ostrich implements Bird.NonFlyingBird {
    @Override
    public boolean canRun() {
        return true;
    }
}

Nested interfaces are used to group logically related interfaces. They are rare in everyday code, but they appear in interview questions as a way to test whether you know the difference in access modifier rules between "nested interface inside an interface" (must be public) and "nested interface inside a class" (any access modifier).


Interface vs Abstract Class: The Ten Differences ​

This comparison appears in almost every Java interview. Know all ten rows. Be able to explain the reasoning behind each difference.

1. Keyword Used ​

An abstract class uses the abstract keyword before class:

java
abstract class Animal { }

An interface uses the interface keyword:

java
interface Flyable { }

2. How a Child Connects ​

A class that extends an abstract class uses extends:

java
class Dog extends Animal { }

A class that uses an interface uses implements:

java
class Eagle implements Flyable { }

3. Types of Methods Allowed ​

An abstract class can have both abstract methods (signature only, no body) and concrete methods (full implementation):

java
abstract class Animal {
    abstract void makeSound();       // abstract: no body
    void breathe() { /* body */ }    // concrete: has a body
}

An interface, before Java 8, could only have abstract methods. From Java 8 onward, interfaces can also have default and static methods with bodies. Java 9 added private methods. The Java 8 and 9 additions will be covered in the next article.

4. Inheritance Chain ​

An abstract class can extend one other class (abstract or concrete) and can also implement multiple interfaces:

java
abstract class Eagle extends Bird implements Flyable, Predator { }

An interface can only extend other interfaces, not classes. And it can extend multiple interfaces:

java
interface NonFlyingBird extends Bird, LivingThing { }

5. Variables and State ​

An abstract class can have any kind of variable: static, non static, final, non final. This means abstract classes can hold mutable state that changes from object to object:

java
abstract class Animal {
    protected String name;       // not static, not final: instance state
    static int count = 0;        // static: shared across all instances
    final int MAX_LEGS = 4;      // final: constant per instance
}

An interface can only have public static final variables, which are constants. An interface cannot hold any mutable state:

java
interface FlightConstants {
    int MAX_HEIGHT = 2000;   // public static final: a constant
}

6. Access Modifiers for Members ​

In an abstract class, members (methods and variables) can use any access modifier: private, protected, public, or default.

In an interface, all members are public by default. Before Java 9, you could not use any other modifier. Java 9 introduced private methods in interfaces, which we will cover later.

7. Multiple Inheritance ​

A class can extend only one other class, whether abstract or concrete. Multiple inheritance through classes is not supported.

An interface supports multiple inheritance. A class can implement any number of interfaces. An interface can extend any number of other interfaces.

8. Relationship Between the Two ​

An abstract class can implement an interface. It does not have to provide implementations for every method; it can leave some abstract for its subclasses to fill in.

An interface cannot implement or extend an abstract class. Interfaces can only extend other interfaces.

9. Constructor ​

An abstract class has a constructor. You cannot call it directly (you cannot do new Animal()), but the constructor exists and is called via super() from a subclass constructor.

An interface has no constructor. There is no mechanism to construct an interface. Interfaces cannot be instantiated in any form.

10. How Abstract Methods Are Declared ​

In an abstract class, an abstract method requires the explicit abstract keyword. And the method can have any access modifier except private (because a private method cannot be overridden, which defeats the purpose):

java
abstract class Animal {
    protected abstract void makeSound();   // 'abstract' keyword required
    public abstract void move();
    // private abstract void breathe();    // forbidden: can't override private
}

In an interface, you do not need the abstract keyword. Any method with just a signature is automatically abstract. And the method is always public:

java
interface Bird {
    void fly();   // automatically public abstract
}

Summary Table ​

PointAbstract ClassInterface
Keywordabstract classinterface
Child keywordextendsimplements
Method typesAbstract and concreteAbstract only (plus default/static in Java 8, private in Java 9)
Inherits fromOne class, many interfacesOnly interfaces (many)
VariablesAny: static or not, final or notAlways public static final
Member visibilityprivate, protected, public, defaultEverything public (Java 9 adds private)
Multiple inheritanceNoYes
RelationshipCan implement interfaceCannot implement abstract class
ConstructorYesNo
Declaring abstract methodsNeeds abstract keyword; can be protected/public/defaultNo keyword needed; always public

Check yourself ​

  1. What does an interface define, and what does it leave to the implementing class?
  2. Which modifiers can a top-level interface have? What can follow extends in an interface declaration?
  3. Give the three reasons interfaces exist.
  4. What does the compiler add to interface methods and to interface fields? Why can an interface method not be final?
  5. Can an implementing class declare an interface method as protected? Must an abstract class implement every interface method?
  6. What access modifiers can a nested interface have inside an interface, and inside a class?
  7. Name five differences between an abstract class and an interface.
Answers
  1. What a class must do (method signatures). The class decides how.
  2. public or default (package-private). Only other interfaces, as a comma-separated list.
  3. Abstraction, polymorphism (an interface type can hold any implementing object, and the method is chosen at runtime), and multiple inheritance without the diamond problem.
  4. Methods become public abstract; fields become public static final (constants). final means "cannot be overridden", but interface methods exist to be implemented.
  5. No, it cannot reduce visibility from public. No: an abstract class may implement some methods and leave the rest; the first concrete class must implement everything left.
  6. Inside an interface: only public. Inside a class: public, protected, private, or default.
  7. For example: abstract class vs interface keyword; extends vs implements; abstract class can have concrete methods and any kind of variable, interface only constants; a class extends one class but implements many interfaces; abstract class has a constructor, interface has none.