Quick Guide to Polymorphism in Java

    Sandeep Panda
    Sandeep Panda
    Share

    Polymorphism means ‘the capacity to take on different forms’. When applied to Java (and other object-oriented programming languages), it describes the language’s ability to process objects of various types and classes through one interface.

    An important example of polymorphism is how a parent class refers to a child class object. Polymorphism occurs when one class is created that extends another one. For instance, let’s consider a class Animal and let Cat be a subclass of the Animal class. So, any cat IS an animal. Here, a Cat satisfies the IS-A relationship for its own type, Cat as well as its super class Animal, and is therefore polymorphic. In fact, any object that satisfies more than one IS-A relationship is polymorphic in nature.

    A subclass inherits the attributes and methods from its superclass (parent). When a method defined in this subclass overrides its parent’s subclass, Java’s polymorphic nature can enable it to perform the same action (method) in a different way. To extend our example, the method feedAnimal() can perform different actions if it’s called on a Cat as opposed to a generic Animal.

    Polymorphism in Java has two types: Runtime polymorphism (dynamic binding) and Compile time polymorphism (static binding). Method overriding is an example of dynamic polymorphism, while method overloading is an example of static polymorphism.

    Note: It’s also legal to say every object in Java is polymorphic in nature, as each one passes an IS-A test for itself and also for Object class.

    Dynamic Polymorphism

    Suppose a subclass overrides a particular method of the superclass. The polymorphic nature of Java will use the overriding method. Let’s say we create an object of the subclass and assign it to the superclass reference. Now, if we call the overridden method on the superclass reference then the subclass version of the same method will be called.

    Have a look at the following example.

    class Vehicle{
        public void move(){
        System.out.println(Vehicles can move!!);
        }
    }
    
    class MotorBike extends Vehicle{
        public void move(){
        System.out.println(MotorBike can move and accelerate too!!);
        }
    }
    
    class Test{
        public static void main(String[] args){
        Vehicle vh=new MotorBike();
        vh.move();    // prints MotorBike can move and accelerate too!!
        vh=new Vehicle();
        vh.move();    // prints Vehicles can move!!
        }
    }

    It should be noted that in the first call to move(), the reference type is Vehicle and the object being referenced is MotorBike. So, when a call to move() is made, Java waits until runtime to determine which object is actually being pointed to by the reference.  In this case, the object is of the class MotorBike. So, the move() method of MotorBike class will be called. In the second call to move(), the object is of the class Vehicle. So, the move() method of Vehicle will be called.

    As the method to call is determined at runtime, this is called dynamic binding, dynamic method dispatch or late binding.

    Static Polymorphism

    In Java, static polymorphism is achieved through method overloading. Method overloading means there are several methods present in a class having the same name but different types/order/number of parameters.

    At compile time, Java knows which method to invoke by checking the method signatures.  So, this is called compile time polymorphism or static binding. The concept will be clear from the following example:

    class DemoOverload{
        public int add(int x, int y){  //method 1
        return x+y;
        }
    
        public int add(int x, int y, int z){ //method 2
        return x+y+z;
        }
    
        public int add(double x, int y){ //method 3
        return (int)x+y;
        }
    
        public int add(int x, double y){ //method 4
        return x+(int)y;
        }
    }
    
    class Test{
        public static void main(String[] args){
        DemoOverload demo=new DemoOverload();
        System.out.println(demo.add(2,3));      //method 1 called
        System.out.println(demo.add(2,3,4));    //method 2 called
        System.out.println(demo.add(2,3.4));    //method 4 called
        System.out.println(demo.add(2.5,3));    //method 3 called
        }
    }

    In the above example, there are four versions of add methods. The first method takes two parameters while the second one takes three. For the third and fourth methods, there is a change of order of parameters. The compiler looks at the method signature and decides which method to invoke for a particular method call at compile time.

    Summary

    An object in Java that passes more than one IS-A tests is polymorphic in nature. Every object in Java passes a minimum of two IS-A tests: one for itself and one for Object class. Static polymorphism in Java is achieved by method overloading. Dynamic polymorphism in Java is achieved by method overriding.

    FAQs about Polymorphism in Java

    What is polymorphic Java?

    Polymorphism is a fundamental concept in object-oriented programming that allows objects of different classes to be treated as objects of a common superclass. Polymorphism in Java enables you to write more flexible and reusable code by allowing different objects to be used interchangeably.

    How does polymorphism work in Java?

    Polymorphism in Java is achieved through method overriding and inheritance. When a subclass inherits from a superclass, it can override methods from the superclass. If you have a reference variable of the superclass type that points to an object of the subclass, the overridden method in the subclass will be invoked when the method is called on that reference.

    What’s the difference between compile-time polymorphism and runtime polymorphism?

    Compile-time polymorphism in Java, also known as method overloading, occurs when multiple methods in the same class have the same name but different parameters. The correct method to be invoked is determined at compile time based on the method signature.
    Runtime polymorphism, also known as method overriding, happens when a subclass provides a specific implementation for a method that is already defined in its superclass. The correct method to be invoked is determined at runtime based on the actual type of the object.

    How is method overriding achieved in Java?

    Method overriding occurs when a subclass provides a new implementation for a method that is already defined in its superclass. To override a method, the method in the subclass must have the same name, return type, and parameters as the method in the superclass. You use the @Override annotation to indicate that you intend to override a method.

    Can I override static methods in Java?

    Static methods cannot be overridden in Java; they can only be hidden. When a subclass defines a static method with the same name and signature as a static method in the superclass, the subclass’s method hides the superclass’s method, but it doesn’t override it.

    How does polymorphism relate to interfaces in Java?

    Interfaces in Java play a crucial role in achieving polymorphism. A class that implements an interface must provide implementations for all the methods declared in the interface. Since multiple classes can implement the same interface, objects of different classes can be treated as objects of the interface type, allowing for polymorphic behavior.

    What is the “super” keyword used for in polymorphism?

    The super keyword is used to refer to the superclass in a subclass. When you want to explicitly call a method or access a field from the superclass, you can use the super keyword. This is particularly useful when you’re overriding a method in the subclass and want to call the superclass’s implementation.

    What are the benefits of using polymorphism in Java?

    Polymorphism in Java promotes code reusability and flexibility. It allows you to write code that can work with a variety of different objects, promoting a modular and maintainable design. It also simplifies code by allowing you to treat related objects uniformly.

    Can polymorphism be used with classes that are not related through inheritance?

    Yes, polymorphism in Java can also be achieved using interfaces. You can create different classes that implement the same interface, allowing objects of these classes to be treated as objects of the interface type.

    How can I use polymorphism to improve code design and maintainability?

    By programming to interfaces and abstract classes, you can write code that focuses on the common behaviors and attributes shared by different objects. This makes your code more adaptable to changes, easier to extend, and less prone to errors when introducing new classes.