top of page

Java Polymorphism: Understanding Dynamic Binding and Method Overriding



📘 Definition


Polymorphism is a core concept in object-oriented programming that allows objects of different types to be treated as if they are of the same type. In Java, there are two main types of polymorphism: compile-time polymorphism and runtime polymorphism. In this answer, we will discuss each topic of polymorphism in Java in detail.


📘 Method Overloading


Method Overloading is a type of compile-time polymorphism where multiple methods have the same name but different parameters. Java determines which method to execute based on the number and types of arguments passed to the method. This allows developers to create methods with the same name but different functionality.

For example:


public class Example {
    public void print(int i) {
        System.out.println("Printing integer: " + i);
    }
    public void print(String s) {
        System.out.println("Printing string: " + s);
    }
}

In this example, we have two methods with the same name, print(), but they take different types of parameters (int and String).


📘 Method Overriding


Method Overriding is a type of runtime polymorphism where a subclass provides a specific implementation of a method that is already provided by its parent class. This allows objects of different types to be treated as if they are of the same type.

For example:


public class Animal {
    public void speak() {
        System.out.println("Animal speaks!");
    }
}

public class Dog extends Animal {
    public void speak() {
        System.out.println("Dog barks!");
    }
}

In this example, we have a parent class Animal with a method speak(). The subclass Dog overrides this method with its own implementation.


📘 Operator Overloading


Operator overloading is a feature in some programming languages, including C++, that allows operators such as +, -, *, /, =, etc. to be redefined for specific user-defined classes or data types. When an operator is overloaded, it can be used with objects of a class or data types in the same way as it would be used with built-in types, such as integers or floating-point numbers.

In Java, operator overloading is not supported. Java does not allow you to redefine the behavior of operators for user-defined classes or data types. Instead, Java provides methods that can perform the same functionality as operators.

For example, let's say we have a class Complex that represents complex numbers, and we want to add two Complex objects using the + operator. In C++, we could overload the + operator to perform this operation:


class Complex {
public:
    double real, imaginary;
    Complex operator+(const Complex& other) {
        Complex result;
        result.real = real + other.real;
        result.imaginary = imaginary + other.imaginary;
        return result;
    }
};

Complex a = {1.0, 2.0};
Complex b = {3.0, 4.0};
Complex c = a + b;
 // c.real = 4.0, c.imaginary = 6.0

In Java, however, we cannot overload the + operator. Instead, we can define a method called add that performs the same operation:


class Complex {
    double real, imaginary;
    
    public Complex add(Complex other) {
        Complex result = new Complex();
        result.real = real + other.real;
        result.imaginary = imaginary + other.imaginary;
        return result;
    }
}

Complex a = new Complex(1.0, 2.0);
Complex b = new Complex(3.0, 4.0);
Complex c = a.add(b); 
// c.real = 4.0, c.imaginary = 6.0

In summary, operator overloading is a feature in some programming languages that allows operators to be redefined for user-defined classes or data types. While Java does not support operator overloading, similar functionality can be achieved using methods.


📘 Dynamic Binding


Dynamic Binding is the process of determining at runtime which method to call, based on the actual type of the object rather than the reference type. This allows objects of different types to be treated as if they are of the same type.

For example:


public class Animal {
    public void speak() {
        System.out.println("Animal speaks!");
    }
}

public class Dog extends Animal {
    public void speak() {
        System.out.println("Dog barks!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal = new Dog();
        animal.speak();
    }
}

In this example, we create an object of type Dog, but we assign it to a variable of type Animal. When we call the speak() method, Java determines at runtime which implementation to call, based on the actual type of the object (which is Dog).


📘 Static Polymorphism (compile-time polymorphism)


Static Polymorphism is a type of compile-time polymorphism where the method overloading occurs. It is also known as method overloading. In this type of polymorphism, the decision of which method to call is made at compile-time.

For example:


public class Example {
    public int add(int a, int b) {
        return a + b;
    }
    public int add(int a, int b, int c) {
        return a + b + c;
    }
}

In this example, we have two methods with the same name, add(), but they take different numbers of parameters. Java determines which method to execute at compile-time, based on the number and types of arguments passed to the method.


📘 Dynamic Polymorphism(runtime polymorphism)


Dynamic Polymorphism is a type of runtime polymorphism where the method overriding occurs. It is also known as method overriding. In this type of polymorphism, the decision of which method to call is made at runtime.

Here's an example:


public class Animal {
    public void speak() {
        System.out.println("Animal speaks!");
    }
}

public class Dog extends Animal {
    public void speak() {
        System.out.println("Dog barks!");
    }
}

public class Cat extends Animal {
    public void speak() {
        System.out.println("Cat meows!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal1 = new Dog();
        Animal animal2 = new Cat();
        
        animal1.speak();
        animal2.speak();
    }
}

In this example, we have a parent class Animal, and two child classes Dog and Cat, both of which override the speak() method of the parent class. We then create two objects animal1 and animal2, which are assigned to Dog and Cat objects, respectively, but are declared as Animal objects.

When we call the speak() method on these objects, Java determines at runtime which implementation to call, based on the actual type of the object. Therefore, when we call animal1.speak(), the speak() method of the Dog class is called, and when we call animal2.speak(), the speak() method of the Cat class is called.

This is an example of dynamic polymorphism because the method call is resolved at runtime based on the actual object type.


In Java, there are two main types of polymorphism: compile-time polymorphism and runtime polymorphism. Method overloading, method overriding, dynamic binding, static polymorphism, dynamic polymorphism, and covariant return type are all examples of polymorphism in Java.


Thanks for reading, and happy coding!


Java Polymorphism: Understanding Dynamic Binding and Method Overriding -> Encapsulation in Object-Oriented Programming (OOP): Definition, Benefits, and Examples.



bottom of page