Interfaces in Java

In Java, an interface is a reference type, similar to a class, that can contain only abstract methods, default methods, static methods, and constant variables (final fields). Interfaces are used to define a contract or blueprint for classes that implement them, specifying what methods should be provided, without dictating how they should be implemented.

Key Characteristics of Interfaces

  1. Abstract Methods: Interfaces typically contain abstract methods, which are methods without a body. Classes that implement the interface must provide the actual implementation for these methods.
  2. Default and Static Methods: Starting from Java 8, interfaces can have default and static methods, which are methods with a body. Default methods can be overridden by implementing classes, while static methods belong to the interface itself.
  3. Constant Variables: Fields in interfaces are implicitly public, static, and final. They are constant values that cannot be modified.
  4. Multiple Inheritance: Interfaces allow a form of multiple inheritance, as a class can implement multiple interfaces.

Defining an Interface

An interface is defined using the interface keyword. By convention, interface names are usually adjectives or descriptive nouns.

// Define an interface named Vehicle
public interface Vehicle {
    // Abstract method (no body)
    void start();

    // Abstract method (no body)
    void stop();
}

In this example, the Vehicle interface declares two abstract methods: start() and stop().

Implementing an Interface

A class that implements an interface must provide implementations for all of the interface’s abstract methods. The implements keyword is used to specify that a class implements an interface.

// Implementing the Vehicle interface in the Car class
public class Car implements Vehicle {
    // Provide implementation for the start method
    @Override
    public void start() {
        System.out.println("Car is starting.");
    }

    // Provide implementation for the stop method
    @Override
    public void stop() {
        System.out.println("Car is stopping.");
    }

    public static void main(String[] args) {
        Car myCar = new Car();
        myCar.start(); // Output: Car is starting.
        myCar.stop();  // Output: Car is stopping.
    }
}

In this example:

  • The Car class implements the Vehicle interface, providing concrete implementations for the start() and stop() methods.
  • The @Override annotation indicates that these methods are overriding the interface’s abstract methods.

Multiple Interface Implementation

A class can implement multiple interfaces, allowing for more flexible code structure.

// Define another interface named Electric
interface Electric {
    void charge();
}

// Implementing both Vehicle and Electric interfaces in the ElectricCar class
public class ElectricCar implements Vehicle, Electric {
    @Override
    public void start() {
        System.out.println("Electric car is starting.");
    }

    @Override
    public void stop() {
        System.out.println("Electric car is stopping.");
    }

    @Override
    public void charge() {
        System.out.println("Electric car is charging.");
    }

    public static void main(String[] args) {
        ElectricCar myElectricCar = new ElectricCar();
        myElectricCar.start();  // Output: Electric car is starting.
        myElectricCar.charge(); // Output: Electric car is charging.
        myElectricCar.stop();   // Output: Electric car is stopping.
    }
}

In this example:

  • The ElectricCar class implements both the Vehicle and Electric interfaces, providing implementations for the methods in both interfaces.

Default Methods in Interfaces

Java 8 introduced default methods in interfaces, which are methods with a body. This feature allows interface designers to add new methods to existing interfaces without breaking existing code.

public interface Vehicle {
    void start();
    void stop();

    // Default method with a body
    default void honk() {
        System.out.println("Honking!");
    }
}

// Implementing the Vehicle interface
public class Bike implements Vehicle {
    @Override
    public void start() {
        System.out.println("Bike is starting.");
    }

    @Override
    public void stop() {
        System.out.println("Bike is stopping.");
    }

    public static void main(String[] args) {
        Bike myBike = new Bike();
        myBike.start(); // Output: Bike is starting.
        myBike.honk();  // Output: Honking!
        myBike.stop();  // Output: Bike is stopping.
    }
}

In this example:

  • The Vehicle interface has a default method honk(), which provides a default implementation.
  • The Bike class implements the Vehicle interface and gains access to the honk() method without explicitly overriding it.

Static Methods in Interfaces

Interfaces can also have static methods, which belong to the interface itself and cannot be overridden by implementing classes.

public interface Utility {
    static void printMessage(String message) {
        System.out.println("Message: " + message);
    }
}

public class UtilityDemo {
    public static void main(String[] args) {
        // Call the static method from the interface
        Utility.printMessage("Hello, World!"); // Output: Message: Hello, World!
    }
}

In this example:

  • The Utility interface defines a static method printMessage(), which can be called using the interface name.

Constant Variables in Interfaces

Fields in an interface are implicitly public, static, and final, meaning they are constants that must be initialized when declared.

public interface Constants {
    // Constant variable
    int MAX_SPEED = 120;
    String VEHICLE_TYPE = "Automobile";
}

public class ConstantsDemo {
    public static void main(String[] args) {
        // Access constant variables from the interface
        System.out.println("Max Speed: " + Constants.MAX_SPEED);       // Output: Max Speed: 120
        System.out.println("Vehicle Type: " + Constants.VEHICLE_TYPE); // Output: Vehicle Type: Automobile
    }
}

In this example:

  • The Constants interface defines constant variables MAX_SPEED and VEHICLE_TYPE, which can be accessed using the interface name.

Functional Interfaces and Lambda Expressions

A functional interface is an interface that contains exactly one abstract method. Functional interfaces can be used with lambda expressions to create concise code for implementing the single abstract method.

// Functional interface with a single abstract method
@FunctionalInterface
interface Greeting {
    void sayHello(String name);
}

public class LambdaDemo {
    public static void main(String[] args) {
        // Using a lambda expression to implement the Greeting interface
        Greeting greeting = (name) -> System.out.println("Hello, " + name);
        greeting.sayHello("Alice"); // Output: Hello, Alice
    }
}

In this example:

  • The Greeting interface is a functional interface with a single abstract method sayHello().
  • A lambda expression is used to implement the interface concisely.

Differences Between Interfaces and Abstract Classes

AspectInterfaceAbstract Class
Method ImplementationCan have abstract, default, and static methodsCan have both abstract and concrete methods
Multiple InheritanceA class can implement multiple interfacesA class can only extend one abstract class
Access ModifiersMethods are implicitly publicMethods can have any access modifier
FieldsFields are public, static, and finalCan have instance fields (not final)
Inheritance KeywordImplemented using implementsExtended using extends
Use CasesUsed to define capabilities or behaviorsUsed for base classes with common functionality