Dynamic binding, also known as late binding or runtime polymorphism, is the process in Java where a method call is resolved at runtime based on the actual object type, not the reference variable's type.
This mechanism is a cornerstone of object-oriented programming, enabling Java's ability to exhibit polymorphic behavior, particularly through method overriding.
How dynamic binding works
At compile-time, the Java compiler only verifies that a method exists in the class hierarchy of the reference variable. However, the definitive link between the method call and its actual implementation is deferred until the program is executing.
Consider a class hierarchy with a superclass Animal and a subclass Dog that overrides the makeSound() method.
Example Code
class Animal {
public void makeSound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Dog barks");
}
}
public class Main {
public static void main(String[] args) {
Animal myAnimal = new Dog(); // Upcasting: Animal reference, Dog object
myAnimal.makeSound(); // Dynamic binding occurs here
}
}
Use code with caution.
Execution flow
- Compile-time: The Java compiler sees the
myAnimalreference of typeAnimaland verifies that theAnimalclass has amakeSound()method. It doesn't know the exact object type, so it only checks the reference type for legality. - Runtime: During execution, the Java Virtual Machine (JVM) determines that
myAnimalis actually holding an instance ofDog. - Dynamic Dispatch: The JVM performs a method lookup based on the actual object type. It finds the overridden
makeSound()method in theDogclass and invokes that specific implementation. - Output: The program prints
"Dog barks", confirming that the overridden method was called, even though the reference was of the superclass type.
Dynamic binding vs. static binding
The behavior of dynamic binding is best understood when contrasted with its compile-time counterpart, static binding.
| Aspect | Dynamic Binding (Late Binding) | Static Binding (Early Binding) |
|---|---|---|
| When it happens | At runtime, when the program is executing. | At compile-time, when the code is translated to bytecode. |
| Methods involved | Instance methods that are overridden in a subclass. | static, private, and final methods, which cannot be overridden. |
| How it's resolved | Based on the actual object type at runtime. | Based on the reference variable type at compile-time. |
| Flexibility | High flexibility, allowing for runtime polymorphism. | Lower flexibility, as the method call is fixed at compile-time. |
| Performance | Can have a slight performance overhead due to the runtime method lookup, but modern JVMs minimize this. | Generally faster, as the method call is resolved early. |
| Example | Method overriding. | Method overloading. |
Characteristics of dynamic binding
- Runtime Resolution: The JVM inspects the object at runtime to find the correct method.
- Enables Polymorphism: Dynamic binding is the mechanism that makes runtime polymorphism possible, allowing a single interface (a superclass or interface reference) to work with multiple underlying object types.
- Depends on Inheritance: It operates within an inheritance hierarchy where subclasses override methods of their superclass.
- Used with Virtual Methods: In Java, all non-static, non-final, and non-private instance methods are "virtual" by default, meaning they can be overridden and are subject to dynamic binding.
Real-world use cases
Dynamic binding is not just a theoretical concept; it is essential for building flexible and extensible Java applications.
- Plugin Architectures: A framework can define an interface for a plugin. A plugin developer implements that interface, and dynamic binding ensures the framework calls the plugin's specific methods at runtime.
- Event Handling: In GUI toolkits like JavaFX, an event listener is registered through an interface. When an event occurs, dynamic binding ensures the correct
actionPerformed()method is called on the object that handles that specific event. - Database Drivers: JDBC relies on dynamic binding. The application code interacts with a generic
java.sql.Connectioninterface, but at runtime, dynamic binding ensures that vendor-specific driver methods are called. - Strategy Design Pattern: An application can choose between different algorithms at runtime by using a common interface. Dynamic binding calls the appropriate strategy's method based on the selected implementation.