Polymorphism in Java
Polymorphism in Java allows entities to exhibit multiple forms, akin to how a person can have different roles or carbon can exist as diamond, graphite, or coal. It's a core concept in OOP for executing tasks in varied ways. Learn more about it here.
What is Polymorphism in Java?
Polymorphism in Java is a foundational principle of object-oriented programming that allows objects to be treated as instances of their parent class rather than their actual class. The term "polymorphism" comes from Greek words meaning "many forms," reflecting its capability to enable a single interface to control access to a generalized form of a method. This concept permits one interface to have multiple implementations.
Types of Polymorphism in Java
Java supports two types of polymorphism:
- Compile-time polymorphism
- Runtime polymorphism
Compile-Time Polymorphism in Java
Compile-time polymorphism in Java, also known as static polymorphism or static method dispatch, is a critical feature in Java that enables multiple methods within the same class to share the same name but differ in their parameter lists. This polymorphism is facilitated through method overloading, where the decision on which method to invoke is made during compile time rather than at runtime.
Method Overloading
Imagine having several methods in a class all named identically, making it challenging for the compiler to differentiate them.
To address this challenge, methods are overloaded by varying the quantity or type of their parameters. This strategy enables a class to house several identically named methods, distinguishable by their unique parameter signatures—either through the variety of parameter types they accept or the number of required parameters.
Example 1
Passing different numbers of arguments to the function.
Output
Explanation
In this example, the CompileTime class demonstrates compile-time polymorphism with two perimeter() functions sharing the same name but differing in parameter counts—one accepts a single argument while the other takes two.
Example 2
Passing different types of argument to the function.
Output
Explanation
The CompileTime class illustrates compile-time polymorphism with two contact() methods: one accepts a name and mobile number (string and long), and the other takes a name and email (two strings).
Read more about What is Compile-Time Polymorphism in Java on Scaler.
Subtypes of Compile-time Polymorphism
- Function Overloading allows defining multiple functions with the same name but different parameters within a scope, increasing coding flexibility. The compiler determines the correct function to call based on the provided arguments.
- Operator Overloading, not extensively supported in Java, unlike C++, refers to giving additional meanings to standard operators depending on their operands, enhancing code intuitiveness.
- Templates facilitate generic programming by enabling functions and classes to handle generic types, promoting code versatility and reusability. Java utilizes generics to ensure type safety and reduce code redundancy.
Runtime Polymorphism in Java
Dynamic Polymorphism in Java, often referred to as runtime polymorphism, involves the resolution of overridden methods at runtime rather than at compile time.
In this scenario, methods overridden in a subclass are accessed via a reference from the parent class, and the specific method to be executed is determined based on the actual type of the object at runtime. The Java Virtual Machine (JVM) identifies the object's type and the corresponding method to invoke.
Dynamic polymorphism arises in situations where multiple classes are linked through inheritance. Establishing an "IS-A" relationship among classes and overriding methods are prerequisites for achieving runtime polymorphism.
Method Overriding
Method overriding occurs when a subclass implements a method that exists in its parent class. This implementation in the subclass is designed to replace the parent class's version of the method, providing a specific behaviour tailored to the subclass.
Rules for overriding a method in Java
- There must be inheritance between classes.
- The method between the classes must be the same(name of the class, number, and type of arguments must be the same).
Example
Output
Explanation
In the above example, the Animal class is parent class, and Dog, Horse, Rabbit are its derived class where the place() method is overridden.
We have created an instance of the Animal class. When an object of every child class is created, the method inside the child class is called. As, the parent class method is overridden by child class.
Read more about Runtime Polymorphism in Java on Scaler.
Subtype of Run-time Polymorphism
Virtual Functions
- Virtual functions enable run-time polymorphism through inheritance and dynamic binding.
- They allow base class functions to be overridden in derived classes for customized behavior.
- When called via a base class reference or pointer, the actual function executed is decided at run-time, depending on the object's actual type.
- This supports dynamic dispatch, allowing code to interact flexibly with objects of various classes using base class pointers or references.
Advantages and Disadvantages of Polymorphism in Java
Advantages
- Enhances code reusability by allowing classes to be used multiple times.
- Improves code readability in compile-time Polymorphism in Java through function naming consistency.
- Supports method consistency between parent and child classes in run-time polymorphism.
- Simplifies debugging by adding structure to code, making it easier to track and fix issues.
Disadvantages
- Complexity in code implementation due to the intricacies of class hierarchies and method overriding.
- Issues with downcasting, as implicit conversion to a subclass type isn't straightforward.
- Potential for misuse or unexpected behavior from subclasses if the superclass design is flawed.
- Performance degradation in runtime polymorphism scenarios, since the method and variable resolutions occur dynamically, impacting execution speed.
Conclusion
- Polymorphism in Java is crucial for object-oriented programming, facilitating flexible and extensible designs.
- It encompasses runtime polymorphism (via method overriding) and compile-time polymorphism (via method overloading), enhancing code utility and maintainability.
- Java implements internal operator overloading and supports both coercion and parametric polymorphism, although it doesn't allow user-defined operator overloading.
- The use of method overriding and inheritance in Java enables efficient code reuse and simplification by allowing subclasses to use and extend superclass functionalities.
- Method overloading in Java allows functions with the same name to perform differently based on input parameters, increasing code readability and efficiency.