Polymorphism is a fundamental concept in object-oriented programming (OOP) that allows objects of different types to be treated as objects of a common type. It promotes code reuse, flexibility, and extensibility. In Java, polymorphism is achieved through method overriding and method overloading.
There are two types of polymorphism in Java:
Compile-time polymorphism, also known as static polymorphism, occurs when the appropriate method to be invoked is determined at compile-time based on the method signature. It is achieved through method overloading.
Method overloading occurs when multiple methods in a class have the same name but different parameters. The methods can have different numbers or types of parameters. Java determines which method to invoke based on the arguments passed during the method call.
class ClassName { returnType methodName(parameterType parameter1) { // Method implementation } returnType methodName(parameterType parameter1, parameterType parameter2) { // Method implementation } // Additional overloaded methods }
class Calculator { int add(int a, int b) { return a + b; } double add(double a, double b) { return a + b; } } // Creating an object of the class Calculator calculator = new Calculator(); // Calling the add() method with different arguments int sum1 = calculator.add(3, 4); // Output: 7 double sum2 = calculator.add(2.5, 3.7); // Output: 6.2 double sum3 = calculator.add(2, 3.5); // Output: 5.5 (implicit conversion)
Runtime polymorphism, also known as dynamic polymorphism, occurs when the appropriate method to be invoked is determined at runtime based on the actual type of the object. It is achieved through method overriding.
Method overriding occurs when a subclass provides its own implementation of a method that is already defined in its superclass. The method in the subclass must have the same signature (name and parameters) as the method in the superclass.
class Superclass { returnType methodName(parameterType parameter1) { // Method implementation } }
class Subclass extends Superclass { @Override returnType methodName(parameterType parameter1) { // Method implementation } } class Shape { void draw() { System.out.println("Drawing a shape."); } } class Circle extends Shape { @Override void draw() { System.out.println("Drawing a circle."); } } class Rectangle extends Shape { @Override void draw() { System.out.println("Drawing a rectangle."); } } // Creating objects of the superclass and subclasses Shape shape1 = new Shape(); Shape shape2 = new Circle(); Shape shape3 = new Rectangle(); // Calling the draw() method shape1.draw(); // Output: Drawing a shape. shape2.draw(); // Output: Drawing a circle. shape3.draw(); // Output: Drawing a rectangle.