Polymorphism, Method Overriding And Method Overloading In Java

Polymorphism is a fundamental concept in object-oriented programming that allows objects to take on many forms.

In Java, polymorphism refers to the ability of a variable, object, or method to take on different forms depending on the context in which it is used. This allows different objects to be treated as if they were of the same type, and for different methods to be called depending on the actual type of the object.

There are two types of polymorphism in Java

  • Compile-time Polymorphism (Method Overloading)
  • Runtime Polymorphism (Method Overriding)

Runtime Polymorphism (Method Overriding)

Method overriding occurs when a subclass provides a specific implementation for a method that is already defined in its superclass. The subclass's method overrides the superclass's method. It is resolved at runtime and hence known as runtime polymorphism.

Importance of Overriding

  • Dynamic Method Dispatch: Allows a method to behave differently based on the object that invokes it.
  • Code Reusability: Enables subclasses to use methods from their parent class and modify their behavior as needed.
  • Implementation Flexibility: Subclasses can provide specific implementations of methods that are more appropriate for their context.

Key Points about Overriding

  • Inherited Methods: Whatever methods the parent class has, they are inherited by the child class. If the child class is not satisfied with the parent class method implementation, it can redefine that method based on its requirement. This process is called overriding.
  • Parent Reference to Child Object: A parent class reference can refer to a child class object. By using this reference, we can call overridden methods, demonstrating runtime polymorphism.
  • Behavior Flexibility: Overriding allows child classes to provide specific implementations that are more suitable for their behavior, while still using the structure and behavior defined in the parent class
  • Dynamic Binding: Method calls are resolved at runtime based on the actual object type, not the reference type. This is known as dynamic binding or late binding and is the essence of runtime polymorphism.
  • Final Methods: Methods declared as final in the parent class cannot be overridden in the child class. The final keyword prevents a method from being modified in any subclass.
  • Method Signature: The method in the child class must have the same name, return type, and parameter list as the method in the parent class. From java 1.5 version onwards we can take covariant return types. According to this child class method return type need not be same as parent class method return type its child type also allowed.
  • Access Modifier: The access modifier of the overridden method must be the same or less restrictive than the method in the parent class. For example, a public method in the parent class cannot be overridden as private in the child class.
  • Annotation: The @Override annotation is used to indicate that a method is overriding a method from the superclass. This is optional but recommended for better readability and error prevention.
  • Use of super Keyword: The super keyword can be used within the child class method to call the method of the parent class. This is useful when you want to extend the functionality of the parent class method rather than completely replace it.
Code Example
Output
The dog barks.
The cat meows.

Compile-time Polymorphism (Method Overloading)

Method overloading allows a class to have more than one method with the same name, provided their parameter lists are different. It is resolved at compile-time and hence known as compile-time polymorphism.

Code Example
Output
Sum of 2 integers: 3
Sum of 3 integers: 6
Sum of 2 doubles: 4.0