Skip to content

Method Overriding and Overloading

1. Define method overriding and method overloading. Illustrate both concepts.

Method Overloading is when a class has multiple methods with the same name but different parameter lists (i.e., different number or type of parameters). It's a way to provide different versions of a method for handling different inputs. This is also known as compile-time polymorphism.

Method Overriding is when a subclass provides a specific implementation for a method that is already defined in its superclass. The method in the subclass must have the same name, return type, and parameters as the one in the parent class. This is the foundation of runtime polymorphism.

java
// Class demonstrating Method Overloading
class Helper {
    void print(String message) {  // Overloaded print method 1
        System.out.println(message);
    }
    
    void print(String message, int times) { // Overloaded print method 2
        for(int i = 0; i < times; i++) {
            System.out.println(message);
        }
    }
}

// Classes demonstrating Method Overriding
class Animal {
    void makeSound() {
        System.out.println("Animal makes a sound");
    }
}

class Cat extends Animal {
    // Overriding the makeSound() method of the Animal class
    @Override
    void makeSound() {
        System.out.println("The cat says: Meow!");
    }
}

public class OverloadingVsOverridingDemo {
    public static void main(String[] args) {
        System.out.println("--- Method Overloading Demo ---");
        Helper helper = new Helper();
        helper.print("Hello"); 
        // Calls the first print() method
        helper.print("Hi", 3); 
        // Calls the second print() method

        System.out.println("\n--- Method Overriding Demo ---");
        Cat myCat = new Cat();
        myCat.makeSound(); 
        // Calls the overridden method in the Cat class
    }
}

2. What are the rules for method overriding in Java?

To correctly override a method:

  • The method name in the subclass must be the same as in the superclass.

  • The parameter list in the subclass must be the same as in the superclass.

  • The return type must be the same or a covariant type (a subtype of the superclass's return type).

  • The access level of the overriding method cannot be more restrictive than the overridden method (e.g., you can override a protected method with public, but not with private).

  • final or static methods cannot be overridden.


3. How is dynamic polymorphism (runtime polymorphism) achieved through method overriding? Provide an example.

Dynamic polymorphism is achieved when a superclass reference variable is used to refer to a subclass object.

When an overridden method is called through this superclass reference, the Java Virtual Machine (JVM) determines which version of the method to execute (the one in the superclass or the one in the subclass) at runtime, based on the actual type of the object being referred to.

This mechanism is also known as "late binding" or "dynamic binding."

shapeRef variable is of type Shape, but it refers to Circle and Rectangle objects. The call to draw() executes the specific version of the method belonging to the actual object at that moment.

java
// Superclass
class Shape {
    void draw() {
        System.out.println("Drawing a shape");
    }
}

// Subclasses
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 ▭");
    }
}

public class PolymorphismDemo {
    public static void main(String[] args) {

		Shape shapeRef; // A reference of type Shape
        shapeRef = new Circle(); // refers to a Circle object
        shapeRef.draw();         
        // Calls the draw() method of the Circle class

        shapeRef = new Rectangle(); // Now refers Rectangle object
        shapeRef.draw();            
        // Calls the draw() method of the Rectangle class
    }
}

Output:

Drawing a circle ○
Drawing a rectangle ▭

Dynamic Method Dispatch

1. What is Dynamic Method Dispatch in Java?

Dynamic Method Dispatch is the technical name for the mechanism that implements runtime polymorphism in Java. It's the process by which a call to an overridden method is resolved at runtime instead of compile time. The decision of which method version to execute is "dispatched" dynamically by the JVM based on the type of the object the reference variable is currently pointing to.

In essence, Dynamic Method Dispatch is the "how" behind the concept of runtime polymorphism explained in the previous section.


2. Illustrate Dynamic Method Dispatch with a programming example.

A simple Example

java
// Demonstrate dynamic method dispatch.
class Sup 
{
	void who() 
	{
		System.out.println("who() in Sup");
	}
}

class Sub1 extends Sup 
{
	void who() 
	{
		System.out.println("who() in Sub1");
	}
}
class Sub2 extends Sup 
{
	void who() 
	{
		System.out.println("who() in Sub2");
	}
}

class DynDispDemo 
{
	public static void main(String[] args) 
	{
		Sup superOb = new Sup();
		Sub1 subOb1 = new Sub1();
		Sub2 subOb2 = new Sub2();
		
		Sup supRef;
		
		supRef = superOb;
		supRef.who();
		
		supRef = subOb1;
		supRef.who();
		
		supRef = subOb2;
		supRef.who();
	}
}
who() in Sup
who() in Sub1
who() in Sub2

The figureRef variable of type Figure is used to call the area() method. The call is dynamically dispatched to the area() method of either the Rectangle or Triangle class, depending on which object figureRef is currently referencing.

java
// A superclass
class Figure {
    double dim1;
    double dim2;

    Figure(double a, double b) {
        dim1 = a;
        dim2 = b;
    }

    double area() {
        System.out.println("Area for Figure is undefined.");
        return 0;
    }
}

// A subclass
class Rectangle extends Figure {
    Rectangle(double a, double b) {
        super(a, b);
    }

    @Override
    double area() {
        System.out.print("Inside Area for Rectangle: ");
        return dim1 * dim2;
    }
}

// Another subclass
class Triangle extends Figure {
    Triangle(double a, double b) {
        super(a, b);
    }

    @Override
    double area() {
        System.out.print("Inside Area for Triangle: ");
        return dim1 * dim2 / 2;
    }
}

public class DynamicDispatchDemo {
    public static void main(String[] args) {
    
        Figure figureRef; // reference variable of type Figure

        Rectangle r = new Rectangle(9, 5);
        Triangle t = new Triangle(10, 8);

        // Point figureRef to a Rectangle object
        figureRef = r;
        System.out.println(figureRef.area());

        // Point figureRef to a Triangle object
        figureRef = t;
        System.out.println(figureRef.area());
    }
}

Output:

Inside Area for Rectangle: 45.0
Inside Area for Triangle: 40.0

Made with ❤️ for students, by a fellow learner.