Defining Interfaces

Introduction

Defining an interface involves declaring the contract that implementing classes must follow.


Basic Syntax

[access_modifier] interface InterfaceName {
    // Constant declarations
    // Method declarations
}

Simple Interface Definition

interface Printable {
    void print();  // Abstract method
}

class Document implements Printable {
    @Override
    public void print() {
        System.out.println("Printing document");
    }
}

public class Main {
    public static void main(String[] args) {
        Printable doc = new Document();
        doc.print();
    }
}

Interface with Multiple Methods

interface Vehicle {
    void start();
    void stop();
    void accelerate();
    void brake();
}

class Car implements Vehicle {
    @Override
    public void start() {
        System.out.println("Car starting");
    }

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

    @Override
    public void accelerate() {
        System.out.println("Car accelerating");
    }

    @Override
    public void brake() {
        System.out.println("Car braking");
    }
}

public class Main {
    public static void main(String[] args) {
        Vehicle car = new Car();
        car.start();
        car.accelerate();
        car.brake();
        car.stop();
    }
}

Interface with Constants

interface MathConstants {
    // public static final (automatically)
    double PI = 3.14159;
    double E = 2.71828;
    int MAX_SIZE = 100;
}

class Calculator implements MathConstants {
    double circleArea(double radius) {
        return PI * radius * radius;  // Using constant
    }

    double exponential(double x) {
        return Math.pow(E, x);
    }
}

public class Main {
    public static void main(String[] args) {
        Calculator calc = new Calculator();
        System.out.println("Area: " + calc.circleArea(5));
        System.out.println("PI value: " + MathConstants.PI);
    }
}

Method Signatures

interface Shape {
    // Method with no parameters
    void draw();

    // Method with parameters
    void resize(double scale);

    // Method with return type
    double area();

    // Method with multiple parameters and return
    String getInfo(String format, boolean detailed);
}

Complete Example: Bank Account

interface BankAccount {
    // Constants
    double MIN_BALANCE = 1000.0;
    double INTEREST_RATE = 4.5;

    // Abstract methods
    void deposit(double amount);
    boolean withdraw(double amount);
    double getBalance();
    void displayAccountInfo();
}

class SavingsAccount implements BankAccount {
    private String accountNumber;
    private String holderName;
    private double balance;

    SavingsAccount(String accountNumber, String holderName, double initialBalance) {
        this.accountNumber = accountNumber;
        this.holderName = holderName;
        this.balance = initialBalance;
    }

    @Override
    public void deposit(double amount) {
        balance += amount;
        System.out.println("Deposited: $" + amount);
    }

    @Override
    public boolean withdraw(double amount) {
        if (balance - amount >= MIN_BALANCE) {
            balance -= amount;
            System.out.println("Withdrawn: $" + amount);
            return true;
        }
        System.out.println("Cannot withdraw. Minimum balance required: $" + MIN_BALANCE);
        return false;
    }

    @Override
    public double getBalance() {
        return balance;
    }

    @Override
    public void displayAccountInfo() {
        System.out.println("Account: " + accountNumber);
        System.out.println("Holder: " + holderName);
        System.out.println("Balance: $" + balance);
        System.out.println("Interest Rate: " + INTEREST_RATE + "%");
    }
}

public class Main {
    public static void main(String[] args) {
        BankAccount account = new SavingsAccount("SA001", "John", 5000);

        account.displayAccountInfo();
        System.out.println();

        account.deposit(2000);
        account.withdraw(1500);
        account.withdraw(5000);  // Will fail - min balance

        System.out.println("\nFinal balance: $" + account.getBalance());
    }
}

Access Modifiers

// Public interface (can be accessed from anywhere)
public interface PublicInterface {
    void method1();
}

// Default (package-private) interface
interface DefaultInterface {
    void method2();
}

// Note: Interfaces cannot be private or protected

Interface Naming Convention

// Adjective ending in -able
interface Comparable { }
interface Serializable { }
interface Cloneable { }
interface Runnable { }

// Noun
interface List { }
interface Set { }
interface Map { }

// Action (verb)
interface ActionListener { }
interface Observer { }

Generic Interface

interface Container<T> {
    void add(T item);
    T get(int index);
    int size();
}

class Box<T> implements Container<T> {
    private T[] items;
    private int count;

    @SuppressWarnings("unchecked")
    Box(int capacity) {
        items = (T[]) new Object[capacity];
        count = 0;
    }

    @Override
    public void add(T item) {
        items[count++] = item;
    }

    @Override
    public T get(int index) {
        return items[index];
    }

    @Override
    public int size() {
        return count;
    }
}

public class Main {
    public static void main(String[] args) {
        Container<String> box = new Box<>(5);
        box.add("Apple");
        box.add("Banana");

        System.out.println(box.get(0));  // Apple
        System.out.println("Size: " + box.size());
    }
}

Interface Extending Multiple Interfaces

interface Readable {
    String read();
}

interface Writable {
    void write(String data);
}

// Interface extending multiple interfaces
interface ReadWrite extends Readable, Writable {
    void close();
}

class File implements ReadWrite {
    private String content = "";

    @Override
    public String read() {
        return content;
    }

    @Override
    public void write(String data) {
        content += data;
    }

    @Override
    public void close() {
        System.out.println("File closed");
    }
}

public class Main {
    public static void main(String[] args) {
        ReadWrite file = new File();
        file.write("Hello World");
        System.out.println(file.read());
        file.close();
    }
}

Real-World Example: Logger Interface

interface Logger {
    // Log levels as constants
    int DEBUG = 1;
    int INFO = 2;
    int WARNING = 3;
    int ERROR = 4;

    // Methods
    void log(String message, int level);
    void setLogLevel(int level);
}

class ConsoleLogger implements Logger {
    private int currentLevel = INFO;

    @Override
    public void log(String message, int level) {
        if (level >= currentLevel) {
            String levelName = getLevelName(level);
            System.out.println("[" + levelName + "] " + message);
        }
    }

    @Override
    public void setLogLevel(int level) {
        this.currentLevel = level;
    }

    private String getLevelName(int level) {
        switch (level) {
            case DEBUG: return "DEBUG";
            case INFO: return "INFO";
            case WARNING: return "WARNING";
            case ERROR: return "ERROR";
            default: return "UNKNOWN";
        }
    }
}

class FileLogger implements Logger {
    private int currentLevel = INFO;

    @Override
    public void log(String message, int level) {
        if (level >= currentLevel) {
            String levelName = getLevelName(level);
            System.out.println("Writing to file: [" + levelName + "] " + message);
        }
    }

    @Override
    public void setLogLevel(int level) {
        this.currentLevel = level;
    }

    private String getLevelName(int level) {
        switch (level) {
            case DEBUG: return "DEBUG";
            case INFO: return "INFO";
            case WARNING: return "WARNING";
            case ERROR: return "ERROR";
            default: return "UNKNOWN";
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Logger console = new ConsoleLogger();
        console.log("Application started", Logger.INFO);
        console.log("Debug message", Logger.DEBUG);  // Won't show (level too low)
        console.log("Warning occurred", Logger.WARNING);
        console.log("Error occurred", Logger.ERROR);

        System.out.println();

        Logger file = new FileLogger();
        file.setLogLevel(Logger.DEBUG);
        file.log("Debug info", Logger.DEBUG);  // Will show now
        file.log("Error in file operation", Logger.ERROR);
    }
}

Functional Interface

Interface with exactly one abstract method.

@FunctionalInterface
interface Calculator {
    int calculate(int a, int b);  // Single abstract method
}

class Addition implements Calculator {
    @Override
    public int calculate(int a, int b) {
        return a + b;
    }
}

public class Main {
    public static void main(String[] args) {
        Calculator add = new Addition();
        System.out.println(add.calculate(10, 20));  // 30

        // Can also use lambda (covered later)
        Calculator multiply = (a, b) -> a * b;
        System.out.println(multiply.calculate(5, 6));  // 30
    }
}

Documentation

/**
 * Interface for shape operations
 * Provides methods for calculating area and perimeter
 *
 * @author Your Name
 * @version 1.0
 */
interface Shape {
    /**
     * Calculates the area of the shape
     * @return the area in square units
     */
    double area();

    /**
     * Calculates the perimeter of the shape
     * @return the perimeter in units
     */
    double perimeter();
}

Best Practices

  1. Name interfaces with adjectives (-able suffix) or nouns
  2. Keep interfaces small (focused on one responsibility)
  3. Use constants for related values
  4. Document thoroughly with JavaDoc
  5. Make methods cohesive (related functionality)
  6. Don’t add unnecessary methods

Common Patterns

1. Strategy Pattern:

interface SortStrategy {
    void sort(int[] array);
}

2. Observer Pattern:

interface Observer {
    void update(String message);
}

3. Factory Pattern:

interface Product {
    void create();
}

Quick Reference

// Basic definition
interface MyInterface {
    // Constant
    int CONSTANT = 100;

    // Abstract method
    void method1();

    // Method with parameters
    void method2(String param);

    // Method with return type
    String method3();
}

// Generic interface
interface Generic<T> {
    void add(T item);
    T get();
}

// Extending interfaces
interface Child extends Parent1, Parent2 {
    void childMethod();
}

// Functional interface
@FunctionalInterface
interface Function {
    int apply(int x);
}

Exam Tips

Remember:

  1. interface keyword to define
  2. All methods implicitly public abstract
  3. All variables implicitly public static final
  4. No method bodies (until Java 8 default methods)
  5. Constants in UPPER_CASE
  6. Can extend multiple interfaces
  7. Use implements keyword in class
  8. @FunctionalInterface for single method
  9. Generic interfaces use type parameters
  10. Document with JavaDoc comments

Common Questions:

  • How to define interface?
  • What are interface variables?
  • Can interface methods have body?
  • How to define constants in interface?
  • What is functional interface?
  • Can interface extend multiple interfaces?
  • Naming conventions for interfaces?
  • What is @FunctionalInterface?
  • How to create generic interface?
  • Best practices for defining interfaces?