Insider of the "doubts" Java dynamic binding mechanism

Source: Internet
Author: User
Tags instance method naming convention

In the process of Java method Invocation, how does the JVM know which class to call the method source code? What's the inside of this? In this article we will expose the static (static binding) and dynamic binding mechanisms (auto binding) of JVM method calls.

★ Static binding mechanism

//the class being called Packagehr.test;classfather{ Public Static voidF1 () {System.out.println ("Father-f1 ()"); }}//calling a static methodImportHr.test.Father; Public classstaticcall{ Public Static voidMain () {father.f1 ();//calling a static method       }}

The statement that executes the method call (Father.f1 ()) in the source code above is compiled by the compiler into an instruction: Invokestatic #13. Let's see how the JVM handles this instruction.

(1) The #13 in the instruction refers to the index entry of the 13th constant table in the constant pool of the Staticcall class (for a constant pool see "class file contents and constant pools"). This constant table (constatn_methodref_info ) records the symbolic references to the method F1 information (including the class name, method name, and return type where the F1 is located). The JVM first finds the fully qualified name of the class where the method F1 is located, based on this symbolic reference: Hr.test.Father.

(2) The Father class is loaded, linked, and initialized by the JVM shortly thereafter.

(3) The direct address of the F1 () method is then found in the method area where the Father class is located, and the direct address is recorded in the constant table of the Staticcall class with a constant pool index of 13. This process is called constant pool parsing , and when you call FATHER.F1 () again later, the bytecode of the F1 method is directly found.

(4) After the resolution of the constant table of the Staticcall constant pool index entry 13 is completed, the JVM can invoke the F1 () method and begin interpreting the instructions in the Execute F1 () method.

Through the process above, we find that after constant pool parsing, the JVM is able to determine where the F1 () method to invoke is specific to the memory. In fact, this information has been recorded in the Staticcall class's constant pool during the compilation phase. This is the way to determine which method to invoke at compile time, which we call a static binding mechanism .

In addition to static methods that are statically modified, all private methods that are modified by the private method, and the method that is overridden by the final modified subclass, are compiled into invokestatic instructions. In addition, the initialization methods of all classes <init> and <clinit> are compiled into invokespecial instructions. The JVM uses a static binding mechanism to successfully invoke these methods.

★ Dynamic binding mechanism

 Packagehr.test;//the called Parent classclassfather{ Public voidF1 () {System.out.println ("Father-f1 ()"); }         Public voidF1 (inti) {System.out.println ("Father-f1 () para-int" +i); }}//the called SubclassclassSonextendsfather{ Public voidF1 () {//methods that override the parent classSystem.out.println ("Son-f1 ()"); }         Public voidF1 (Charc) {System.out.println ("Son-s1 () Para-char" +c); }}//Calling MethodsImporthr.test.*; Public classautocall{ Public Static voidMain (string[] args) {Father Father=NewSon ();// polymorphicFATHER.F1 ();//Print Result: Son-f1 ()    }}

There are three important concepts in the above source code: polymorphic (polymorphism) , method overrides, method overloading . The results of the printing are all quite clear, but how does the JVM know that f.f1 () is calling the subclass Sun method instead of the Father method? Before explaining this problem, let's start by simply talking about a very important data structure for JVM management-the method table .

While the JVM loads the class, it holds a lot of information in the method area for this class (see Java Virtual Machine architecture). One of them is a data structure called a method table. It records the direct address of the current class and all of its superclass's visible method bytecode in memory as an array. Is the method table in the source code above in the method area of the father and Sun classes:

There are two features in the Method table: (1) Subclass Method table inherits the method of the parent class, such as Father extends Object. (2) The same method (same method signature: Method name and Parameter list) is the same as the index in the method table of all classes. For example, the F1 () in the Father Method table and the F1 () in the Son Method table are located in the 11th item of the respective method table.

For the above source code, the compiler will first compile the main method into the following bytecode directive:

Multibyte-code instruction code for polymorphic calls
0  New// open a son object's memory space in the heap and press the object reference into the operand stack 3  dup  4  //  7  // popup operand stack son object reference pressed into local variable 1 8  // Remove object reference in local variable 1 push-in operand stack 9  // Call F1 () method  return

The detailed invocation procedure of the invokevirtual instruction is this:

(1) The #15 in the invokevirtual directive refers to the index entry of the 15th constant table in the constant pool of the Autocall class. This constant table (constatn_methodref_info ) records the symbolic references to the method F1 information (including the class name, method name, and return type where the F1 is located). The JVM will first find the fully qualified name of the class that invokes the method F1, based on this symbolic reference: Hr.test.Father. This is because the object father of the class that calls the method F1 is declared as the father type.

(2) Find the method F1 in the method table of the father type, and if found, F1 the method to the index entry 11 in the method table (for example) to the 15th constant pool in the Autocall class ( constant pool resolution ). One thing to note here: if there is no method F1 in the Father Type method table, then even if the method table is in the son type, the compile time will not pass. Because the object father of the class that calls the method F1 is declared as Father type.

(3) There is a aload_1 instruction before invoking the invokevirtual instruction, which pushes the reference of the Son object that is created in the heap into the operand stack. The invokevirtual instruction then finds the son object in the heap based on the reference to the Son object, and then further finds the method table of the type that the son object belongs to. The process is as follows:

(4) This is the index entry for the method table in the #15 constant table resolved in step (2), you can locate the method F1 () in the Son Type method table, and then find the memory space where the method bytecode resides through the direct address.

Obviously, depending on the declared type (father) of the object (father), you cannot determine where the method F1 is called, and you must determine where the F1 method resides based on the object type that father actually created in the heap. In the process of running the program, we call the dynamic binding mechanism by means of the method table of dynamically created objects.

The process above clearly reflects how the JVM locates the exact method in the case of a polymorphic invocation of the method coverage. But how does the following calling method JVM be located? (father and son types are still used in the code above)

 Public class autocall{       publicstaticvoid  main (string[] args) {             Father Father =new  Son ();              Char c= ' a ';              // Printed Result: Father-f1 ()  para-int ()}       }

The problem is that there are no methods in the Fahter type that are signed as F1 (char). However, the print results show that the JVM called the F1 (int) method in the father type and did not call the F1 (char) method in the son type.

According to the procedure described above, it is first clear that the JVM first resolves the constant pool based on the type father declared by the object father (that is, the index entry in the Father Method table instead of the symbol reference in the constant pool). If the father does not match the "appropriate" method, the constant pool resolution cannot be performed, which is not available during the compile phase.

So what's the "right" way? Of course, the method of signing exactly the same way is naturally appropriate. But what if the parameter type in the method cannot be found in the declared type? For example, the above code calls FATHER.F1 (char), and the father type does not have a method signature of F1 (char). In fact, the JVM will find a way to "make it Happen" by automatically transforming the parameters to find the "right" approach. For example, char can be automatically transformed into int, then the Father class can be matched to this method (about the automatic transformation of Java can be found in the "confusion" Java type transformation between). But there is one more question, what if the automatic transformation of the discovery can "make it" out of two ways? For example, the following code:

classfather{ Public voidF1 (Object o) {System.out.println ("Object"); }     Public voidF1 (Double[] D) {System.out.println ("Double[]"); }    } Public classdemo{ Public Static voidMain (string[] args) {NewFather (). F1 (NULL);//print Result: double[]    }}

Null can be referenced to any reference type, so how does the JVM determine the "appropriate" method? An important criterion is that if one method can accept any parameter passed to another method, the first method is relatively inappropriate. For example, the above code: any arguments passed to the F1 (double[]) method can be passed to the F1 (Object) method, but not the other way, then the F1 (double[]) method is more appropriate. So the JVM will invoke this more appropriate method.

★ Summary

(1) All private methods, static methods, constructors, and initialization methods <clinit> all use static binding mechanisms. The symbolic reference of the calling method in the constant pool is indicated at the compiler stage, and only one constant pool resolution is required for the JVM to run.

(2) The invocation of the class object method must adopt a dynamic binding mechanism during the run.

First, the "appropriate" method is found based on the object's declaration type (the type of the object reference). The steps are as follows:

① This method is most appropriate if you can match a method in the declaration type to exactly the same method signature (the parameter type is the same).

② in the case that article ① can not be satisfied, to find a way to "do". The standard is to match the parameter types after they are automatically transformed. If multiple auto-transformed method signatures F (a) and F (b) are matched, the following criteria are used to determine the appropriate method: The parameters passed to the F (a) method can be passed to F (B), and F (a) is most appropriate. Conversely F (B) is most appropriate.

③ if the "appropriate" method is still not found in the claim type, the compilation phase fails.

Then, based on the actual type of object created in the heap, find the corresponding method table from which to determine the location of the specific method in memory.

★ Overwrite (Override)

An instance method can overwrite (override) All instance methods that have the same signature that are accessible in its superclass, thus enabling dynamic dispatch (dispatch); in other words, the VM chooses the override method to invoke based on the instance's run-time type. Overwrite is the basis of object-oriented programming technology and is the only form of name reuse that is not universally discouraged:

class base{      publicvoid  f () {}}classextends  base{       publicvoid  f () {}}

★ Hidden (hide)

A domain, static method, or member type can hide (hide) All fields, static methods, or member types that have the same name (the same method signature on the method) that are accessible in its superclass. Hiding a member will prevent it from being inherited.

class base{      publicstaticvoid  f () {}}classextends Base  {      privatestaticvoid f () {}   // hides Base. F ()}

★ Reload (Overload)
Methods in a class can overload (overload) Another method, as long as they have the same name and different signatures. The overloaded method specified by the call is selected at compile time.

class circuitbreaker{      publicvoid f (int i) {}    //int overloading public      void F (string s) {}   //string overloading}

★ Masking (Shadow)
A variable, method, or type can individually obscure (shadow) all variables, methods, or types that have the same name within a closed text range. If an entity is obscured, you cannot refer to it by its simple name, and sometimes you cannot refer to it at all, depending on the entity.

class whoknows{    static String sentence= "I don ' t know.";     Public Static void Main (string[] args){           String sentence= "I don ' t know.";  Shadows static field           System.out. println (sentence);  // Prints local variable     }}

Although shadowing is usually discouraged, there is a common idiom that does cover it. Constructors often reuse a domain name from its own class as a parameter to pass the value of the named field. This idiom is not without risk, but most Java programmers agree that this style brings more benefits than
Its risk:

class belt{      privateint size;  // Parameter Shadows Belt. Size       Public Belt (int  size) {           this. size=size;      }} 

★ Masking (obscure)

A variable can obscure a type that has the same name, as long as they are all in the same range: If the name is used for a range of variables and types, then it is referenced to the variable. Similarly, a variable or a type can obscure a package. Masking is the only form of two name reuse in different namespaces that include: variables, packages, methods, or types. If a type or a package is obscured, then you cannot pass its simple
Name refers to it, except in a context where the syntax allows only one name to appear in its namespace. Following a naming convention can greatly eliminate the possibility of concealment:

 Public class obscure{      static String System;   Obscures type Java.lang.Systempublic      staticvoid  Main (String [] args)            //  Next line won ' t Compile:system refers to static field            System. Prin TLN ("Hello, obscure world!");}      }

Insider of the "doubts" Java dynamic binding mechanism

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.