SyntaxStudy
Sign Up
Java Abstraction and Polymorphism
Java Beginner 1 min read

Abstraction and Polymorphism

Abstraction means exposing only the essential details of an object and hiding the implementation complexity. In Java, abstraction is achieved through abstract classes and interfaces. An abstract class defines a common base with some implementation and some abstract (unimplemented) methods that subclasses must override. Interfaces define a pure contract with no state. Polymorphism means "many forms." In Java there are two kinds. Compile-time polymorphism is achieved through method overloading. Runtime polymorphism is achieved through method overriding: a subclass provides its own implementation of a method declared in a parent class. When you call a method on a reference variable, the JVM dispatches the call to the actual class of the object, not the declared type of the variable. This is called dynamic dispatch. Runtime polymorphism enables you to write code that works with a base type and automatically handles all subtypes correctly. For example, a list of Shape objects can contain Circles, Rectangles, and Triangles, and calling draw() on each invokes the correct implementation for the actual shape. This reduces the need for type checks and switch statements, making code more extensible.
Example
import java.util.List;

// Abstract base class
abstract class Shape {
    private String color;

    Shape(String color) { this.color = color; }

    public String getColor() { return color; }

    // Abstract method — every concrete Shape must implement this
    public abstract double area();

    // Concrete method — shared by all shapes
    public void describe() {
        System.out.printf("%s [color=%s, area=%.2f]%n",
            getClass().getSimpleName(), color, area());
    }
}

class Circle extends Shape {
    private final double radius;
    Circle(String color, double radius) { super(color); this.radius = radius; }

    @Override public double area() { return Math.PI * radius * radius; }
}

class Rectangle extends Shape {
    private final double width, height;
    Rectangle(String color, double width, double height) {
        super(color);
        this.width = width; this.height = height;
    }
    @Override public double area() { return width * height; }
}

class Triangle extends Shape {
    private final double base, height;
    Triangle(String color, double base, double height) {
        super(color);
        this.base = base; this.height = height;
    }
    @Override public double area() { return 0.5 * base * height; }
}

public class PolymorphismDemo {
    public static void main(String[] args) {
        List<Shape> shapes = List.of(
            new Circle("red", 5),
            new Rectangle("blue", 4, 6),
            new Triangle("green", 3, 8)
        );

        double totalArea = 0;
        for (Shape s : shapes) {
            s.describe();               // dynamic dispatch — correct subtype called
            totalArea += s.area();
        }
        System.out.printf("Total area: %.2f%n", totalArea);
    }
}