Data Types and Operators
(Non-Primitive Data Types)
Control Flow Statements
Conditional Statements
Looping Statements
Branching Statements
Object-Oriented Programming (OOP)
Exception Handling
Collections Framework
Overview of Collections
Java I/O
Multithreading
GUI Programming with Swing
Advanced Topics
JAVA CODE
Java Basics
Working with Objects
Arrays, Conditionals, and Loops
Creating Classes and Applications in Java
More About Methods
Java Applet Basics
Graphics, Fonts, and Color
Simple Animation and Threads
More Animation, Images, and Sound
Managing Simple Events and Interactivity
Creating User Interfaces with the awt
Windows, Networking, and Other Tidbits
Modifiers, Access Control, and Class Design
Packages and Interfaces
Exceptions
Multithreading
Streams and I/O
Using Native Methods and Libraries
Under the Hood
Java Programming Tools
Working with Data Structures in Java
Advanced Animation and Media
Fun with Image Filters
Client/Server Networking in Java
Emerging Technologies
appendix A :- Language Summary
appendix B :- Class Hierarchy Diagrams
appendix C The Java Class Library
appendix D Bytecodes Reference
appendix E java.applet Package Reference
appendix F java.awt Package Reference
appendix G java.awt.image Package Reference
appendix H java.awt.peer Package Reference
appendix I java.io Package Reference
appendix J java.lang Package Reference
appendix K java.net Package Reference
appendix L java.util Package Reference

Runtime polymorphism in Java, also known as dynamic method dispatch, is a process in which a call to an overridden method is resolved at runtime rather than compile time. This is a core concept in object-oriented programming and is achieved through method overriding.

Key Concepts

  1. Method Overriding: When a subclass provides a specific implementation for a method that is already defined in its superclass. The overridden method in the subclass should have the same name, return type, and parameters as the method in the superclass.

  2. Upcasting: When a subclass object is assigned to a superclass reference. This is essential for runtime polymorphism.

How Runtime Polymorphism Works

When a method is called on an object, the JVM determines which method to execute based on the actual object’s class, not the reference type. This decision happens at runtime, allowing the program to exhibit different behaviors depending on the object’s actual class.

Example

Consider the following example to illustrate runtime polymorphism:

				
					class Animal {
    void sound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {
    void sound() {
        System.out.println("Dog barks");
    }
}

class Cat extends Animal {
    void sound() {
        System.out.println("Cat meows");
    }
}

public class TestPolymorphism {
    public static void main(String[] args) {
        Animal a;
        a = new Dog();
        a.sound(); // Output: Dog barks

        a = new Cat();
        a.sound(); // Output: Cat meows
    }
}

				
			

Explanation

  1. Class Hierarchy: We have a superclass Animal with a method sound(), and two subclasses Dog and Cat that override the sound() method.
  2. Upcasting: The Animal reference a is used to refer to objects of both Dog and Cat.
  3. Method Call Resolution: When a.sound() is called, the JVM determines the actual object type (Dog or Cat) at runtime and invokes the corresponding overridden method.

Benefits of Runtime Polymorphism

  1. Flexibility and Maintainability: New subclasses can be added with minimal changes to existing code.
  2. Extensibility: Code can be extended to include new functionalities without altering existing code.
  3. Dynamic Method Invocation: Allows methods to be invoked based on the object’s runtime type, facilitating more dynamic and flexible code.

Real-World Use Case

Consider a graphical user interface (GUI) framework where different types of widgets (buttons, text fields, checkboxes) are drawn on the screen. Each widget can be represented as a subclass of a common base class Widget, which has a method ‘draw()‘. At runtime, the framework can decide which ‘draw()‘ method to invoke based on the actual widget type, enabling dynamic and flexible rendering.

				
					abstract class Widget {
    abstract void draw();
}

class Button extends Widget {
    void draw() {
        System.out.println("Drawing a button");
    }
}

class TextField extends Widget {
    void draw() {
        System.out.println("Drawing a text field");
    }
}

public class TestGUI {
    public static void main(String[] args) {
        Widget w;
        w = new Button();
        w.draw(); // Output: Drawing a button

        w = new TextField();
        w.draw(); // Output: Drawing a text field
    }
}

				
			

Runtime polymorphism in Java allows methods to be overridden in subclasses and enables the JVM to determine which method to call at runtime based on the actual object’s class. This enhances flexibility, maintainability, and extensibility in object-oriented programming.

Scroll to Top