As an object-oriented language, Java has three characteristics: encapsulation, inheritance and polymorphism. Polymorphism is allowing objects of different classes to respond to the same message. Based on polymorphism, some types of coupling relationships can be eliminated, which can be substituted and expandable. The method of using polymorphism in Java mainly consists of implementing an interface to implement a method of an abstract class that overrides a method of the parent class.
The underlying principle of Java polymorphism
The underlying implementation of polymorphism is dynamic binding, in which the method invocation is associated with the method implementation at run time. Dynamic binding involves a lot of details about the JVM, and it takes a great deal of detail to write it all down, so this article is just a brief description, and there are other articles on the details one by one to share.
static binding and dynamic binding
There are five method invocation directives for the JVM, namely:
- Invokestatic: Call static method;
- Invokespecial: Invoking instance constructors <init> methods, private methods, and parent class methods;
- Invokevirtual: Call virtual method;
- Invokeinterface: Call interface method, run time to determine the specific implementation;
- Invokedynamic: The runtime parses the referenced method dynamically and then executes it to support the dynamic type language.
Where invokestatic and invokespecial are used for static binding, invokevirtual and invokeinterface are used for dynamic binding. As you can see, dynamic binding is mainly applied to virtual methods and interface methods.
Static bindings are determined at compile time because static methods, constructor methods, private methods, and parent class methods can be uniquely determined. Symbolic references to these methods are parsed into direct references during the parsing phase of the class load. Therefore, these methods are also called non-virtual methods, and the opposite is the virtual method.
The method invocation of a virtual method is associated with a method implementation (that is, dispatch), which is determined at compile time, known as Static dispatch, such as overloading of the method, and is determined at run time, called Dynamic dispatch, such as the method's overwrite. Object methods are essentially virtual methods.
It is particularly stated here that the final method can be uniquely determined because it cannot be overwritten, so the Java language specification specifies that the final method belongs to a non-virtual method, but is still invoked with the invokevirtual directive. The concepts of static binding, dynamic binding and virtual and non-virtual methods are two different concepts.
Multi-State implementation
As mentioned in the previous Java threading Knowledge supplements, the stack frame of the current method call is stored in the virtual machine stack, which stores the local variable table, the Operation Stack, the dynamic connection, the return address, and other additional information in the stack frame. The multi-state implementation process is the process of the method call dynamic dispatch, through the information of the stack frame to find the specific implementation of the called method, and then use the specific implementation of the direct reference to complete the method call.
Taking the invokevirtual directive as an example, in execution, it can be broadly divided into the following steps:
1, first from the Operation Stack to find the actual type of object class;
2, find the class in the same way as the method signed by the method, if there is access to return the direct reference to this method, if there is no access to the error java.lang.IllegalAccessError;
3, if the 2nd step can not find a matching method, go to search class of the parent class, according to the inheritance of the relationship between the bottom-up sequence of steps 2nd;
4, if the 3rd step can not find a matching method, the error java.lang.AbstractMethodError;
As you can see, if a subclass overrides a method of a parent class, in a polymorphic call, the dynamic binding process first determines that the actual type is a subclass, and first searches the methods in the subclass. This process is the essence of method coverage.
In fact, commercial virtual machines typically use virtual method tables and interface method tables in order to ensure performance, rather than performing the steps above each time. As an example of a virtual method table, the virtual method table is populated during the parsing phase of the class load, where a direct reference to all the methods is stored. In other words, dynamic dispatch is completed when the virtual method table is populated.
In a virtual method table of a subclass, if a subclass overrides a method of the parent class, the direct reference to the method points to the implementation of the subclass, and the subclasses do not override those methods, such as the method of object, directly referencing the implementation of the parent class or object.
Write at the end: Welcome message discussion, add attention, continuous UPDATE!!!
The underlying principle of Java polymorphism