// Base class
class Animal {
    public void makeSound() {
        System.out.println("Animal makes a sound");
    }
}

// Subclasses
class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Dog barks");
    }
}

class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Cat meows");
    }
}

// Runtime polymorphism
Animal animal1 = new Dog();
Animal animal2 = new Cat();
animal1.makeSound(); // "Dog barks" - calls Dog's method
animal2.makeSound(); // "Cat meows" - calls Cat's method

// Polymorphic array
Animal[] animals = {new Dog(), new Cat(), new Animal()};
for (Animal animal : animals) {
    animal.makeSound(); // Calls appropriate method for each
}

// Compile-time polymorphism (Method Overloading)
class Calculator {
    public int add(int a, int b) {
        return a + b;
    }
    
    public double add(double a, double b) {
        return a + b;
    }
    
    public int add(int a, int b, int c) {
        return a + b + c;
    }
}

Calculator calc = new Calculator();
int sum1 = calc.add(5, 3);        // Calls int version
double sum2 = calc.add(5.5, 3.2); // Calls double version
int sum3 = calc.add(1, 2, 3);     // Calls three-parameter version

// Interface polymorphism
interface Shape {
    double area();
}

class Circle implements Shape {
    private double radius;
    
    public Circle(double radius) {
        this.radius = radius;
    }
    
    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
}

class Rectangle implements Shape {
    private double width, height;
    
    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }
    
    @Override
    public double area() {
        return width * height;
    }
}

// Polymorphic usage
Shape[] shapes = {
    new Circle(5.0),
    new Rectangle(4.0, 6.0)
};

for (Shape shape : shapes) {
    System.out.println("Area: " + shape.area());
}