Java Polymorphism - Complete Guide
Introduction to Polymorphism
Polymorphism means 'many forms'. In Java, it allows objects of different classes to be treated as objects of a common superclass. There are two types of polymorphism: compile-time (method overloading) and runtime (method overriding).
Runtime polymorphism is achieved through method overriding, where a subclass provides a specific implementation of a method that is already defined in its superclass.
Polymorphism Concepts
- ✅ Method Overriding - Subclass provides specific implementation of superclass method
- ✅ Method Overloading - Multiple methods with same name but different parameters
- ✅ Upcasting - Treating subclass object as superclass type
- ✅ Dynamic Method Dispatch - JVM determines which method to call at runtime
Method Overloading Example
Method overloading is a form of compile-time polymorphism where multiple methods share the same name but have different parameters. The method to be executed is determined at compile time.
class Calculator {
// Method to add two integers
public int add(int a, int b) {
return a + b;
}
// Method to add three integers
public int add(int a, int b, int c) {
return a + b + c;
}
// Method to add two doubles
public double add(double a, double b) {
return a + b;
}
}
public class OverloadingExample {
public static void main(String[] args) {
Calculator calculator = new Calculator();
System.out.println("Sum of two integers: " + calculator.add(5, 10));
System.out.println("Sum of three integers: " + calculator.add(5, 10, 15));
System.out.println("Sum of two doubles: " + calculator.add(5.5, 10.5));
}
}
Sum of two integers: 15 Sum of three integers: 30 Sum of two doubles: 16.0
Upcasting Example
Upcasting is the process of treating a subclass object as an instance of its superclass. This allows you to write code that works with general superclass types, making it more flexible and reusable.
class Animal {
public void makeSound() {
System.out.println("Animal sound");
}
}
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Bark");
}
}
public class UpcastingExample {
public static void main(String[] args) {
// Upcasting: Dog object treated as Animal
Animal myDog = new Dog();
myDog.makeSound(); // Output: Bark
}
}
Bark
Dynamic Method Dispatch Example
Dynamic method dispatch is a mechanism where the JVM determines which version of an overridden method to call at runtime, based on the actual object type.
class Vehicle {
public void start() {
System.out.println("Vehicle started");
}
}
class Car extends Vehicle {
@Override
public void start() {
System.out.println("Car started");
}
}
class Bike extends Vehicle {
@Override
public void start() {
System.out.println("Bike started");
}
}
public class DynamicDispatchExample {
public static void main(String[] args) {
Vehicle vehicle;
vehicle = new Car();
vehicle.start(); // Output: Car started
vehicle = new Bike();
vehicle.start(); // Output: Bike started
}
}
Car started Bike started
Polymorphism Example
// Superclass
class Shape {
public void draw() {
System.out.println("Drawing a shape");
}
public double calculateArea() {
return 0;
}
}
// Subclass 1
class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public void draw() {
System.out.println("Drawing a circle with radius " + radius);
}
@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
}
// Subclass 2
class Rectangle extends Shape {
private double length;
private double width;
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
@Override
public void draw() {
System.out.println("Drawing a rectangle " + length + "x" + width);
}
@Override
public double calculateArea() {
return length * width;
}
}
public class PolymorphismExample {
public static void main(String[] args) {
// Polymorphic array
Shape[] shapes = new Shape[3];
shapes[0] = new Circle(5.0);
shapes[1] = new Rectangle(4.0, 6.0);
shapes[2] = new Shape();
// Process each shape polymorphically
for (Shape shape : shapes) {
shape.draw();
System.out.println("Area: " + shape.calculateArea());
System.out.println();
}
}
}
Drawing a circle with radius 5.0 Area: 78.53981633974483 Drawing a rectangle 4.0x6.0 Area: 24.0 Drawing a shape Area: 0.0