Difference Interfaces and Abstract Classes


In Java, interfaces and abstract classes are used to define abstract types that allow you to specify methods that must be implemented by other classes. However, they have key differences and are suited for different use cases.

Interfaces:

An interface is a contract that defines a set of methods that implementing classes must provide. It is used to achieve multiple inheritance in Java, as a class can implement multiple interfaces.

  • Key Features:
    • Only method signatures (no implementation) in Java 7 and earlier.
    • From Java 8 onwards, interfaces can have default and static methods with implementations.
    • Can have public, default, and static methods (Java 8+).
    • Fields are implicitly public, static, and final.
  • Syntax Example:
                
                interface Animal {
                    void eat();
                    void sleep();
                }
    
                class Dog implements Animal {
                    public void eat() {
                        System.out.println("Dog is eating.");
                    }
    
                    public void sleep() {
                        System.out.println("Dog is sleeping.");
                    }
                }
                
                
  • Use Cases:
    • When you need to define a contract for classes to implement.
    • For multiple inheritance (since Java doesn’t support multiple class inheritance).
    • When different classes need to implement the same behavior but from different inheritance hierarchies.

Abstract Classes:

An abstract class is a class that cannot be instantiated on its own and may contain both abstract methods (without implementation) and concrete methods (with implementation).

  • Key Features:
    • Can have constructors, fields, and fully implemented methods.
    • Can have access modifiers (private, protected, public) for methods and variables.
    • Supports single inheritance only (a class can extend only one abstract class).
  • Syntax Example:
                
                abstract class Vehicle {
                    int speed;
    
                    abstract void start();
    
                    void stop() {
                        System.out.println("Vehicle is stopping.");
                    }
                }
    
                class Car extends Vehicle {
                    void start() {
                        System.out.println("Car is starting.");
                    }
                }
                
                
  • Use Cases:
    • When you want to provide common code (implementation) for all subclasses.
    • To define an abstract base class with shared behavior and enforce the implementation of specific methods.
    • When you need to maintain state (fields) that will be shared among subclasses.

Key Differences:

Aspect Interface Abstract Class
Inheritance Multiple inheritance (implements multiple) Single inheritance (extends only one)
Methods No implementation (except default/static methods) Can have both abstract and concrete methods
Constructors No constructors Can have constructors
Fields Public, static, final only Can have instance variables (with any modifier)
Access Modifiers Methods are public by default Methods can be private, protected, or public
Use Case Define a contract for unrelated classes Share code among related classes

When to Use Which?

  • Use Interfaces:
    • When you want to define a contract that multiple classes should follow.
    • When your classes don’t share a common ancestor (different class hierarchies).
  • Use Abstract Classes:
    • When you want to provide some common behavior (code) to multiple related classes.
    • When you need to maintain state (fields) across subclasses.

What is Composition in Java?

Composition is a design principle in which one class contains a reference to another class and delegates tasks to it. For example:

        
        class Engine {
            void start() {
                System.out.println("Engine started.");
            }
        }

        class Car {
            private Engine engine;

            Car() {
                this.engine = new Engine();
            }

            void startCar() {
                engine.start();
            }
        }
        
        

Why Favor Composition Over Inheritance?

Inheritance creates a tight coupling between parent and child classes and can lead to fragile base class problems. Composition, on the other hand, promotes more flexible and maintainable code.

Benefits of Composition in Java OOP
  1. Greater Flexibility
    • You can change behavior at runtime by swapping components.
    • Example: Swap out one engine with another (e.g., DieselEngine, ElectricEngine).
  2. Loose Coupling
    • Composition leads to less dependency between classes.
    • Easier to refactor or reuse components in different contexts.
  3. Better Encapsulation
    • Internal implementation details are hidden behind the composed object.
    • Follows the "black-box" principle.
  4. Avoids Inheritance Pitfalls
    • No issues like method name clashes or unexpected behavior from overriding.
    • Reduces risks of fragile base class and inheritance chain complexities.
  5. Promotes Code Reuse
    • You can reuse composed classes across multiple systems without modifying them.
  6. Supports Dynamic Behavior
    • Strategy Pattern and Decorator Pattern use composition to change behavior dynamically at runtime.
Drawbacks of Inheritance
  • Rigid structure (tight coupling)
  • Can lead to deep and complex class hierarchies
  • Breaks encapsulation when subclass depends too much on the parent class's implementation
When to Use Composition
  • When objects have distinct behaviors that might change
  • When you need multiple capabilities but Java does not support multiple inheritance
  • When you want to decouple systems for better testability and maintainability