- Assume that a class named SuperClass defines a method named method .
- Assume that a class named SubClass extends SuperClass and overrides the method named method .
- Assume that a reference to an object of the class named SubClass is assigned to a reference variable named ref of type SuperClass .
- Assume that the method named
method is then called on the reference variable using the following syntax:
- ref.method()
- Result: The version of the method named method that will actually be executed is the overridden version in the class named SubClass , and is not the version that is defined in the class named SuperClass, even though the reference to the object of type SubClass is stored in a variable of type SuperClass .
This is runtime polymorphism in a nutshell, which is sometimes also referred to as late-binding.
Runtime polymorphism is very powerful
As you gain more experience with Java, you will learn that much of the power of OOP using Java is centered on runtime polymorphism using class inheritance, interfaces, and method overriding. (The use of interfaces for polymorphism will be discussed in a future module.)
An important attribute of runtime polymorphism
The decision as to which version of the method to execute
- is based on the actual type of object whose reference is stored in the reference variable, and
- is not based on the type of the reference variable on which the method is called.
Why is it called runtime polymorphism?
The reason that this type of polymorphism is often referred to as runtime polymorphism is because the decision as to which version of the method to execute cannot be made until runtime. The decision cannot be made at compile time.
Why defer the decision?
The decision cannot be made at compile time because the compiler has no way of knowing (when the program is compiled) the actual type of the object whose reference will be stored in the reference variable .
In an extreme case, for example, the object might be de-serialized at runtime from a network connection of which the compiler has no knowledge.
Could be either type
For the situation described above, that de-serialized object could just as easily be of type SuperClass as of type SubClass . In either case, it would be valid to assign the object's reference to the same superclass reference variable.
If the object were of the SuperClass type, then a call to the method named method on the reference would cause the version of the method defined in SuperClass , and not the version defined in SubClass , to be executed. (The version executed is determined by the type of the object and not by the type of the reference variable containing the reference to the object.)
Sample Program
Let's take a look at a sample program that illustrates runtime polymorphism using class inheritance and overridden methods. The name of the program is Poly03 . A complete listing of the program is shown in Listing 7 near the end of the module.
Listing 1 shows the definition of a class named A , which extends the class named Object .
(Remember that any class that doesn't extend some other class automatically extends Object by default, and it is not necessary to show that explicitly as I did in this example.)