Dynamic Method Dispatch in Java
Last updated on 25th Sep 2020, Artciles, Blog
Method overriding is one of the ways in which Java supports Runtime Polymorphism. Dynamic method dispatch is the mechanism by which a call to an overridden method is resolved at run time, rather than compile time.When an overridden method is called through a superclass reference, Java determines which version(superclass/subclasses) of that method is to be executed based upon the type of the object being referred to at the time the call occurs. Thus, this determination is made at run time.
At run-time, it depends on the type of the object being referred to (not the type of the reference variable) that determines which version of an overridden method will be executed.A superclass reference variable can refer to a subclass object. This is also known as upcasting. Java uses this fact to resolve calls to overridden methods at run time.
Subscribe For Free Demo
Error: Contact form not found.
Therefore, if a superclass contains a method that is overridden by a subclass, then when different types of objects are referred to through a superclass reference variable, different versions of the method are executed. Here is an example that illustrates dynamic method dispatch:
Advantages of Dynamic Method Dispatch
- Dynamic method dispatch allows Java to support overriding of methods which is central for run-time polymorphism.
- It allows a class to specify methods that will be common to all of its derivatives, while allowing subclasses to define the specific implementation of some or all of those methods.
- It also allows subclasses to add its specific methods subclasses to define the specific implementation of some.
Static vs Dynamic binding
Static binding is done during compile-time while dynamic binding is done during run-time.Private, final and static methods and variables uses static binding and bonded by compiler while overridden methods are bonded during runtime based upon type of runtime object
Upcasting in Java
When the Parent class reference variable refers to a Child class object, it is known as Upcasting. In Java this can be done and is helpful in scenarios where multiple child classes extend one parent class. In those cases we can create a parent class reference and assign child class objects to it.
In this example, we are creating two classes Bike and Splendor. Splendor class extends Bike class and overrides its run() method. We are calling the run method by the reference variable of the Parent class. Since it refers to the subclass object and subclass method overrides the Parent class method, the subclass method is invoked at runtime.
Since method invocation is determined by the JVM not compiler, it is known as runtime polymorphism.In computer science, dynamic dispatch is the process of selecting which implementation of a polymorphic operation (method or function) to call at run time. It is commonly employed in, and considered a prime characteristic of, object-oriented programming (OOP) languages and systems.
Object-oriented systems model a problem as a set of interacting objects that enact operations referred to by name. Polymorphism is the phenomenon wherein somewhat interchangeable objects each expose an operation of the same name but possibly differing in behavior. As an example, a File object and a Database object both have a StoreRecord method that can be used to write a personnel record to storage. Their implementations differ. A program holds a reference to an object which may be either a File object or a Database object. Which it is may have been determined by a run-time setting, and at this stage, the program may not know or care which. When the program calls StoreRecord on the object, something needs to choose which behavior is enacted. If one thinks of OOP as sending messages to objects, then in this example the program sends a StoreRecord message to an object of unknown type, leaving it to the run-time support system to dispatch the message to the right object. The object enacts whichever behavior it implements.
Dynamic dispatch contrasts with static dispatch, in which the implementation of a polymorphic operation is selected at compile time. The purpose of dynamic dispatch is to defer the selection of an appropriate implementation until the run time type of a parameter (or multiple parameters) is known.
Dynamic dispatch is different from late binding (also known as dynamic binding). Name binding associates a name with an operation. A polymorphic operation has several implementations, all associated with the same name. Bindings can be made at compile time or (with late binding) at run time. With dynamic dispatch, one particular implementation of an operation is chosen at run time. While dynamic dispatch does not imply late binding, late binding does imply dynamic dispatch, since the implementation of a late-bound operation is not known until run time.
Single and Multiple Dispatch
The choice of which version of a method to call may be based either on a single object, or on a combination of objects. The former is called single dispatch and is directly supported by common object-oriented languages such as C++, Java, Objective-C, Swift, JavaScript, and Python. In these and similar languages, one may call a method for division with syntax that resembles
where the parameters are optional. This is thought of as sending a message named divide with parameter divisor to dividend. An implementation will be chosen based only on the dividend’s type (perhaps rational, floating point, matrix), disregarding the type or value of the divisor.
By contrast, some languages dispatch methods or functions based on the combination of operands; in the division case, the types of the dividend and divisor together determine which divide operation will be performed. This is known as multiple dispatch. Examples of languages that support multiple dispatch are Common Lisp, Smalltalk, Dylan, and Julia.
Dynamic dispatch mechanisms
A language may be implemented with different dynamic dispatch mechanisms. The choices of the dynamic dispatch mechanism offered by a language to a large extent alter the programming paradigms that are available or are most natural to use within a given language.
Normally, in a typed language, the dispatch mechanism will be performed based on the type of the arguments (most commonly based on the type of the receiver of a message). Languages with weak or no typing systems often carry a dispatch table as part of the object data for each object.
This allows instance behavior as each instance may map a given message to a separate method.Some languages offer a hybrid approach.Dynamic dispatch will always incur an overhead so some languages offer static dispatch for particular methods.
C++ implementation
C++ uses early binding and offers both dynamic and static dispatch. The default form of dispatch is static. To get dynamic dispatch the programmer must declare a method as virtual.C++ compilers typically implement dynamic dispatch with a data structure called a virtual function table (vtable) that defines the name-to-implementation mapping for a given class as a set of member function pointers. (This is purely an implementation detail; the C++ specification does not mention vtables.)
Instances of that type will then store a pointer to this table as part of their instance data. This is complicated when multiple inheritance is used. Since C++ does not support late binding, the virtual table in a C++ object cannot be modified at run-time, which limits the potential set of dispatch targets to a finite set chosen at compile time.Type overloading does not produce dynamic dispatch in C++ as the language considers the types of the message parameters part of the formal message name. This means that the message name the programmer sees is not the formal name used for binding.
Go and Rust implementation
In Go and Rust, a more versatile variation of early binding is used. Table pointers are carried with object references as ‘fat pointers’ (‘interfaces’ in Go, or ‘trait objects’ in Rust).
This decouples the supported interfaces from the underlying data structures. Each compiled library needn’t know the full range of interfaces supported in order to correctly use a type, just the specific vtable layout that they require. Code can pass around different interfaces to the same piece of data to different functions. This versatility comes at the expense of extra data with each object reference, which is problematic if many such references are stored persistently.
Smalltalk implementation
Smalltalk uses a type-based message dispatcher. Each instance has a single type whose definition contains the methods. When an instance receives a message, the dispatcher looks up the corresponding method in the message-to-method map for the type and then invokes the method.
Because a type can have a chain of base types, this look-up can be expensive. A naive implementation of Smalltalk’s mechanism would seem to have a significantly higher overhead than that of C++ and this overhead would be incurred for each and every message that an object receives.
Real Smalltalk implementations often use a technique known as inline caching that makes method dispatch very fast. Inline caching basically stores the previous destination method address and object class of the call site (or multiple pairs for multi-way caching). The cached method is initialized with the most common target method (or just the cache miss handler), based on the method selector. When the method call site is reached during execution, it just calls the address in the cache. (In a dynamic code generator, this call is a direct call as the direct address is back patched by cache miss logic.) Prologue code in the called method then compares the cached class with the actual object class, and if they don’t match, execution branches to a cache miss handler to find the correct method in the class.
A fast implementation may have multiple cache entries and it often only takes a couple of instructions to get execution to the correct method on an initial cache miss. The common case will be a cached class match, and execution will just continue in the method.Out-of-line caching can also be used in the method invocation logic, using the object class and method selector. In one design, the class and method selector are hashed, and used as an index into a method dispatch cache table.
As Smalltalk is a reflective language, many implementations allow mutating individual objects into objects with dynamically generated method lookup tables. This allows altering object behavior on a per object basis. A whole category of languages known as prototype based languages has grown from this, the most famous of which are Self and JavaScript. Careful design of the method dispatch caching allows even prototype based languages to have high performance method dispatch.Many other dynamically typed languages, including Python, Ruby, Objective-C and Groovy use similar approaches.
In Java, Dynamic method dispatch is a technique in which object refers to superclass but at runtime, the object is constructed for subclass.
i.e. It is a technique in which a superclass reference variable refers to a subclass object. It is also known as Upcasting in java.
Java uses this mechanism to resolve a call to an overridden method at runtime rather than compile time. The overridden method is called through the reference variable of a superclass. The determination of the method to be called is based on the object being referred to by the reference variable.
In the dynamic dispatch method technique, we can declare a superclass reference variable equal to sub class object like this:
- SuperClass sc = new ChildClass(); // sc is a superclass reference variable which is pointing to a child class object.
Dynamic dispatch method is important because it is a process through which Java implements runtime polymorphism. Let’s understand the dynamic method dispatch more clearly by different example programs.
Java Dynamic Method Dispatch Example Programs
Program source code 1:
Let’s create a Java program to illustrate Dynamic Method Dispatch using hierarchical inheritance.
- void m1()
- public class A {
- package dynamicMethodDispatchProgram;
- {
- System.out.println(“m1-A”);
- }
- }
- public class B extends A
- {
- // Overriding m1() method.
- void m1()
- {
- System.out.println(“m1-B”);
- }
- }
- public class C extends B
- {
- // Overriding m1() method.
- void m1()
- {
- System.out.println(“m1-C”);
- }
- }
- public class Test
- {
- public static void main(String[] args)
- {
- A a = new A(); // Object of type A. That is “a” is a reference variable of type A which is pointing to object of class A.
- a.m1();
- B b = new B(); // Object of type B. “b” is a reference variable of type B which is pointing to object of class B.
- b.m1();
- C c = new C(); // Object of type C. “c” is a reference variable of type C which is pointing to object of class C.
- c.m1();
- A a2; // A reference variable of type A.
- a2 = b; // Reference a1 refers to Class B’s object.
- a2.m1();
- a2 = c; // Reference a1 refers to Class C’s object.
- a2.m1();
- B b2 = c; // Reference variable b2 of type B refers to class C’s object.
- b2.m1();
- }
- }
Output:
- 1. m1-A
- 2. m1-B
- 3. m1-C
- 4. m1-B
- 5. m1-C
- 6. m1-C
Explanation:
In the preceding program, we have created one superclass called A and its two subclasses B and C. These subclasses override m1( ) method.
1. Inside the main() method in class Test, initially, objects of type A, B, and C are declared.
a. When a.m1(); will be executed, it will call method m1() of class A because reference variable “a” is pointing towards the object of class A.b.
b.m1(); will call m1() of class B because reference variable “b” refers to the object of class B.
c. c.m1(); will invoke m1() of class C because reference variable “c” is pointing towards the object of class C.
2. When A a2 is declared, initially it will point to null.
a. a2.m1(); will call m1() of class B because “a2” is a reference variable of type A but it is pointing towards class B’s object.
b. a2.m1(); will call m1() of class C. This is because “a2” is referring to class C’s object.
3. b2.m1(); will call m1() of class C because “b2” of type B is pointing to class C’s object.
If you have any problem understanding the above concept then first, I will recommend to you for going below the topic. In this topic, we have explained in detail the working concept of Java compiler and JVM which you can understand easily.
This is an example of dynamic method dispatch. Let’s see the next example program.
Program source code 2:
- package dynamicMethodDispatchProgram;
- public class X
- {
- X()
- {
- System.out.println(“Parent class constructor”);
- m1();
- }
- void m1()
- {
- System.out.println(“Parent method”);
- }
- }
- public class Y extends X
- {
- Y()
- {
- System.out.println(“Child class constructor”);
- }
- void m1()
- {
- System.out.println(“Child class method”);
- }
- }
- public class Demo extends Y
- {
- public static void main(String[] args)
- {
- Y y = new Y();
- y.m1();
- X x = new Y();
- x.m1();
- Y y2 = new Demo();
- y2.m1();
- }
- }
Output:
Parent class constructor
Child class method
Child class constructor
Child class method
Parent class constructor
Child class method
Child class constructor
Child class method
Parent class constructor
Child class method
Child class constructor
Child class method
Explanation of flow of execution of the above program:
1. Inside the main() method of Demo class, when the statement A a = new A(); will be executed, the control of execution will be immediately transferred to class Y’s constructor.
From there, the super class constructor will be called and the control of execution will be transferred to class X’s constructor. The first output will be printed “Parent class constructor”.
2. From the super class constructor, m1() method of class Y will be called because the reference variable “y” is pointing to the object of class Y. The second output will be “Child class method”.
3. After the execution of m1() method, the control of execution will be again immediately transferred to class Y’s constructor. The third output will be “Child class constructor”.
4. y.m1(); will call m1() of class Y because “y” refers to an object of class Y. The fourth output is “Child class method”.
Similarly, for the other two statements.
Are you looking training with Right Jobs?
Contact Us- The Most Popular Java Applications Used World-wide
- Resources To Help You Learn Java Programming
- Top Skills that Boosts Java Developer Salaries
- Java Interview Questions and Answers
- JAVA Tutorial
Related Articles
Popular Courses
- Python Online Training
11025 Learners
- C And C Plus Plus Online Training
12022 Learners
- Dot Net Training
11141 Learners
- What is Dimension Reduction? | Know the techniques
- Difference between Data Lake vs Data Warehouse: A Complete Guide For Beginners with Best Practices
- What is Dimension Reduction? | Know the techniques
- What does the Yield keyword do and How to use Yield in python ? [ OverView ]
- Agile Sprint Planning | Everything You Need to Know