Chapter 39 of 57

Interfaces in Java

Imagine you are creating a payment system. You want every payment method to provide a pay() operation, but you don't want to decide inside the general design exactly how every payment method will work.

A credit card, UPI, and PayPal can all make payments, but the actual process is different for each one.

An interface allows us to define a common set of methods that a class agrees to provide.

In simple words, an interface acts like a contract. It tells a class what it should do, while the class provides the actual implementation.

Creating an Interface

We create an interface using the interface keyword.

interface Payment {
    void pay();
}

Here, Payment is an interface and pay() is a method that classes implementing the interface must provide.

To use an interface, a class uses the implements keyword.

class CreditCardPayment implements Payment {

    @Override
    public void pay() {
        System.out.println("Payment made using credit card.");
    }
}

Now CreditCardPayment has provided the implementation of pay().

We can create an object:

CreditCardPayment payment = new CreditCardPayment();

payment.pay();

Output:

Payment made using credit card.

Multiple Classes Can Implement the Same Interface

The real benefit becomes clear when multiple classes implement the same interface.

interface Payment {
    void pay();
}

class CreditCardPayment implements Payment {

    @Override
    public void pay() {
        System.out.println("Payment made using credit card.");
    }
}

class UPIPayment implements Payment {

    @Override
    public void pay() {
        System.out.println("Payment made using UPI.");
    }
}

Both classes follow the same Payment contract, but they implement pay() differently.

Payment payment1 = new CreditCardPayment();
Payment payment2 = new UPIPayment();

payment1.pay();
payment2.pay();

Output:

Payment made using credit card.
Payment made using UPI.

This is also an example of polymorphism.

Interface Methods

Traditionally, methods declared inside an interface are abstract methods that don't contain an implementation.

For example:

interface Animal {
    void sound();
}

A class implementing this interface must provide the method:

class Dog implements Animal {

    @Override
    public void sound() {
        System.out.println("Dog barks.");
    }
}

Notice that the method is public.

When implementing an interface method, you cannot reduce its visibility. Since interface methods are public, the implementing method must also be public.

Interfaces Can Have Constants

Variables declared in an interface are automatically treated as constants. They are public, static, and final.

For example:

interface Payment {
    double TAX_RATE = 0.18;
}

We can access it using the interface name:

System.out.println(Payment.TAX_RATE);

You cannot change the value later:

Payment.TAX_RATE = 0.20; // Error

For most beginner programs, the main thing to remember is that interface fields are constants.

Multiple Interfaces

One important feature of interfaces is that a class can implement multiple interfaces.

Java doesn't allow a class to extend multiple classes:

class Dog extends Animal, Pet { // Error
}

But a class can implement multiple interfaces:

interface Animal {
    void eat();
}

interface Pet {
    void play();
}

class Dog implements Animal, Pet {

    @Override
    public void eat() {
        System.out.println("Dog is eating.");
    }

    @Override
    public void play() {
        System.out.println("Dog is playing.");
    }
}

Now Dog must provide implementations for both eat() and play().

Dog dog = new Dog();

dog.eat();
dog.play();

Output:

Dog is eating.
Dog is playing.

This is one of the major advantages of interfaces.

Interface Reference

Just like with inheritance, we can use an interface as a reference type.

For example:

interface Animal {
    void sound();
}

class Dog implements Animal {

    @Override
    public void sound() {
        System.out.println("Dog barks.");
    }
}

We can write:

Animal animal = new Dog();

animal.sound();

Output:

Dog barks.

The reference is of type Animal, but the actual object is a Dog.

This allows us to write flexible code that can work with different classes implementing the same interface.

Interface with Multiple Implementations

For example:

interface Notification {
    void send();
}

class EmailNotification implements Notification {

    @Override
    public void send() {
        System.out.println("Sending email.");
    }
}

class SMSNotification implements Notification {

    @Override
    public void send() {
        System.out.println("Sending SMS.");
    }
}

Now we can have:

Notification notification = new EmailNotification();
notification.send();

notification = new SMSNotification();
notification.send();

Output:

Sending email.
Sending SMS.

The same interface allows us to work with different implementations.

Default Methods

Modern Java interfaces can also contain methods with an implementation using the default keyword.

For example:

interface Animal {

    void sound();

    default void sleep() {
        System.out.println("Animal is sleeping.");
    }
}

A class implementing the interface must provide sound(), but it can directly use the default sleep() method.

class Dog implements Animal {

    @Override
    public void sound() {
        System.out.println("Dog barks.");
    }
}

Now:

Dog dog = new Dog();

dog.sound();
dog.sleep();

Output:

Dog barks.
Animal is sleeping.

A class can also override the default method if it needs different behavior.

Interface vs Abstract Class

Interfaces and abstract classes are both used for abstraction, but they are useful in different situations.

An abstract class can contain instance variables, constructors, normal methods, and abstract methods.

An interface is mainly used to define a contract or capability that classes agree to provide.

For example:

Abstract class:
Animal
 ├── Dog
 └── Cat

Interface:
Flyable
 ├── Bird
 └── Airplane

An abstract class usually represents a common type or base class, while an interface can represent a capability or behavior.

A class can extend only one class but can implement multiple interfaces.

A Complete Example

Let's create a simple notification system:

interface Notification {
    void send();
}

class EmailNotification implements Notification {

    @Override
    public void send() {
        System.out.println("Sending email notification.");
    }
}

class SMSNotification implements Notification {

    @Override
    public void send() {
        System.out.println("Sending SMS notification.");
    }
}

class Main {
    public static void main(String[] args) {

        Notification notification1 = new EmailNotification();
        Notification notification2 = new SMSNotification();

        notification1.send();
        notification2.send();
    }
}

Output:

Sending email notification.
Sending SMS notification.

The interface defines what a notification should be able to do, while each class decides how that operation works.

The main idea to remember is:

An interface defines a contract that tells classes what they must do, while the implementing classes decide how to do it.