Code Example 2: dynamic polymorphism

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

class Dog extends Animal {
    public void makeSound() {
        System.out.println("The dog barks");
    }
}

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

public class DynamicPolymorphismExample {
    public static void main(String[] args) {
        Animal animal1 = new Animal();
        Animal animal2 = new Dog();
        Animal animal3 = new Cat();

        animal1.makeSound();
        animal2.makeSound();
        animal3.makeSound();
    }
}

In this example, the Animal class has a makeSound method that is overridden in the Dog and Cat classes. When the main method is called, three objects are created, one each of the Animal, Dog, and Cat classes.

The makeSound method of each object is then called. Since Dog and Cat classes override the makeSound method of the Animal class, the behavior of the makeSound method depends on the type of the object.

When the makeSound method is called on the animal1 object, it will call the makeSound method of the Animal class and print “The animal makes a sound” to the console. When the makeSound method is called on the animal2 object, it will call the makeSound method of the Dog class and print “The dog barks” to the console. Similarly, when the makeSound method is called on the animal3 object, it will call the makeSound method of the Cat class and print “The cat meows” to the console.

This demonstrates that the behavior of the makeSound method is dynamically bound to the type of the object at runtime, which is a key feature of dynamic polymorphism.