An interface answers a design question every real system faces: how do you let unrelated classes be used interchangeably, as long as they can all do a certain job? A payment system doesn't care whether it's talking to a credit card or a UPI handler — it only cares that both can pay(). That "only cares that it can" idea is what an interface captures.
This tutorial builds interfaces from the contract idea up, through implements, multiple inheritance, and the Java 8 default methods that reshaped the feature. For the head-to-head with abstract classes, see abstract class vs interface.
An interface is a contract
An interface declares what a class can do without saying how. It lists method signatures; the implementing class supplies the bodies.
interface Payment {
void pay(double amount); // no body: just the promise
}
Any class that claims to be a Payment must provide a pay method. The interface is a promise the class signs.
class CreditCardPayment implements Payment {
@Override
public void pay(double amount) {
System.out.println("Paid " + amount + " by credit card");
}
}
class UpiPayment implements Payment {
@Override
public void pay(double amount) {
System.out.println("Paid " + amount + " via UPI");
}
}
Both classes are unrelated — neither extends the other — yet both are Payment. That is the power: code can accept a Payment and work with either, a direct expression of polymorphism.
public class Checkout {
static void process(Payment method, double amount) {
method.pay(amount); // don't care which implementation
}
public static void main(String[] args) {
process(new CreditCardPayment(), 1500);
process(new UpiPayment(), 300);
}
}
What to notice: process is written against the Payment interface, not a concrete class. You can add WalletPayment tomorrow and process needs no changes. Coding to interfaces, not implementations, is one of the most repeated pieces of design advice in Java for exactly this reason.
implements vs extends
Two keywords, two jobs:
extends— a class inherits from one class, or an interface inherits from other interfaces.implements— a class promises to fulfil one or more interfaces.
A single class can do both at once, and it can implement several interfaces separated by commas:
class SmartPhone extends Device implements Camera, GpsSensor {
// must implement every method from Camera and GpsSensor
}
This is Java's answer to multiple inheritance. You can extend only one class, but implement as many interfaces as you need. That restriction exists to avoid the diamond problem — if you could extend two classes that both define the same field and method, the compiler couldn't decide which to inherit. Interfaces sidestep it because they carry no instance state. The same reasoning is covered from the inheritance side in our inheritance tutorial.
What interfaces can and cannot hold
Before Java 8, an interface was pure abstraction — only method signatures and constants. The rules that still hold:
- All declared methods are implicitly
public abstract(unless they are default/static/private). - All fields are implicitly
public static final— they are constants, not instance state. - You cannot instantiate an interface with
new Payment(); you instantiate a class that implements it.
interface Config {
int MAX_RETRIES = 3; // implicitly public static final
void reload();
}
MAX_RETRIES is a constant shared by everyone; there is no per-object state in an interface. This is the key structural difference from an abstract class, which can hold instance fields.
Default methods: how Java 8 evolved interfaces
There was a real problem before Java 8: adding a method to a widely-used interface broke every class that implemented it, because they all suddenly lacked the new method. Default methods solved this — a method with a body that implementers inherit automatically.
interface Vehicle {
void start(); // abstract: must implement
default void honk() { // default: optional to override
System.out.println("Beep!");
}
}
class Bike implements Vehicle {
@Override
public void start() {
System.out.println("Kick start");
}
// honk() inherited for free
}
public class Main {
public static void main(String[] args) {
Bike b = new Bike();
b.start(); // Kick start
b.honk(); // Beep! (from the default method)
}
}
This is exactly how List.sort() and Collection.stream() were added to existing interfaces without breaking millions of lines of code. A class can still override a default method if it wants different behavior.
Pro tip: Default methods are for evolving interfaces safely, not for dumping shared logic. If two interfaces a class implements both define a default method with the same signature, the class is forced to override it and resolve the conflict explicitly — Java makes you choose rather than guessing.
Interfaces can also carry static methods (utility helpers tied to the interface, called as InterfaceName.method()) and, since Java 9, private methods to share code between default methods.
Functional interfaces and lambdas
An interface with exactly one abstract method is a functional interface, and it can be the target of a lambda expression. This is the bridge between OOP and the functional style Java 8 introduced.
@FunctionalInterface
interface Calculator {
int operate(int a, int b);
}
public class Main {
public static void main(String[] args) {
Calculator add = (a, b) -> a + b; // lambda
Calculator multiply = (a, b) -> a * b;
System.out.println(add.operate(3, 4)); // 7
System.out.println(multiply.operate(3, 4)); // 12
}
}
The lambda (a, b) -> a + b is an implementation of Calculator — no separate class needed. The @FunctionalInterface annotation asks the compiler to fail if you accidentally add a second abstract method. Built-in examples are Runnable, Comparator, and everything in java.util.function; go deeper in the functional interfaces tutorial.
Interfaces can extend interfaces
An interface can build on others with extends, forming a hierarchy of contracts.
interface Readable {
String read();
}
interface Writable {
void write(String data);
}
interface ReadWrite extends Readable, Writable {
// inherits read() and write(); may add more
}
A class implementing ReadWrite must supply both read() and write(). This is exactly how the collections framework is structured — List extends Collection, so every list is also a collection, and any code that accepts a Collection will happily take a List.
Where interfaces show up in real Java
Interfaces are not an academic exercise — they are the backbone of the standard library and every framework you will touch. Comparable lets your objects be sorted. Runnable lets them run on a thread. List, Map, and Set are interfaces whose concrete classes (ArrayList, HashMap, HashSet) you pick based on need, while your method signatures stay written against the interface. In Spring Boot, you define a repository interface and the framework generates the implementation for you at runtime.
The habit to build is declaring variables and parameters by their interface type, not their concrete type:
// prefer the interface on the left-hand side
List<String> names = new ArrayList<>(); // not ArrayList<String> names
Writing List<String> names instead of ArrayList<String> names means you can swap ArrayList for LinkedList later by changing one line, and every method that takes a List keeps working. This small discipline is what "program to an interface, not an implementation" looks like in day-to-day code.
Interview note: "Since interfaces now have default methods, why do we still need abstract classes?" is a common follow-up. The short answer: abstract classes can hold mutable instance state and constructors; interfaces cannot. Get the full comparison on the abstract class vs interface page and practice framing it on our Java OOP interview questions.
Where to go next
Interfaces are how you achieve loose coupling and true abstraction in Java, so read that next to see the bigger design principle. Then compare them carefully with abstract classes in abstract class vs interface so you know which to reach for.
When you start building real projects — REST controllers, service layers, repositories — you'll write and consume interfaces constantly, and that hands-on design practice is a core part of the Java Full Stack course. The full roadmap is in the Java learning hub.
Frequently Asked Questions
What is the difference between a class and an interface in Java?
Can an interface have method bodies in Java?
Why can a class implement multiple interfaces but extend only one class?
What is a functional interface?
Can an interface extend another interface?
Want to Build Your Career in Java Full Stack with AI?
Join CodeBegun and train with working industry engineers — Explore the Program

