Java dynamic binding and static binding random thoughts

Java dynamic binding and static binding random thoughts

The reason why I wrote this blog is because I encountered a very strange phenomenon in the process of writing code. I think it can only be explained by dynamic binding and static binding, so I learned about the implementation of dynamic binding and static binding. The principle, I did learn a lot in this process, I am afraid that I will forget it later, so I recorded it in the form of a blog.
Why is it called cranky, because this blog mainly records what I have learned and some of my questions and answers, and there is no strong logic, so it is called cranky!

The realization principle of Java dynamic binding and static binding

Regarding the realization principle, the normative and accurate explanation can be found here .
I would like to summarize it in my own words so that I can understand it better.

Static binding implementation principle: When a method using static binding is called for the first time, the java bytecode level is to call a constant table in the constant pool, which describes the specific information of the method (including the detailed class name, function name, and return value, which are stored in the CONSTANT_Methodref_info structure). At this time, the JVM will first load the class to which the function belongs (if the class has not been loaded before), and then, according to the specific information of the method, find the method code in the method table of the corresponding class (Method table) After finding the specific address, put it directly into the constant pool, and put it in the position of the corresponding constant table. This process is called constant pool resolution. After parsing, when this method is called for the second time, since the address is stored in the constant pool, it does not need to be parsed again, just use the address to execute the corresponding code block!

Dynamic binding implementation principle: The constant pool parsing process using the dynamic binding method is similar to the static binding, the difference is that the corresponding constant table is not replaced by the specific address of the code block, but the index of the function in the method table. (According to the design of the method table, the same method of the subclass and the parent class will have the same index in the method table). At runtime, according to the type of the actual instance that calls this function, this type is used to find the corresponding method table of this type, and then the method table is used to find the location of the actual code block. Through one more step of parsing, we have achieved dynamic binding!

For a better understanding, let’s put two pictures:
the first one is the picture of the constant pool:
write picture description here
in this constant pool, there are 28 items, each of which is called a constant table and has a corresponding structure. There are the following types:
write picture description here
The structure of CONSTANT_Methodref_info is as follows:
write picture description here
tag (1 byte) is the tag bit, class_index (2 bytes) points to a CONSTANT_Class_info data item, this data item represents the type (class) of the referenced method name_and_type_index (2 bytes ) points to a CONSTANT_NameAndType_info that describes the name and descriptor of the referenced method.

Then there is a diagram of the method table:
write picture description here
from which we can see that the subclass will copy the method table of the parent class, and then add new content. If it is rewritten, the address of the corresponding function will be modified. . (This also means that the same function in the subclass, the index in the method table of the parent class is the same)


have a bee in one's bonnet

Knowing the working principle of dynamic binding and static binding, I began to think about it.
1. What kind of method uses static binding? What kind of methods use dynamic binding?
Answer: Methods decorated with static, final, and private, as well as constructors, are all static bindings. For other methods, use dynamic binding!

2. For the virtual machine, how to determine whether to use static binding or dynamic binding?
A: In Java bytecode, there are five instructions for calling a function: invokestatic, invokespecial, invokevirtual, invokeinterface, and invokedynamic. The functions mentioned in 1 that should use static binding are called through invokestatic and invokespecial. Therefore, when the virtual machine sees these two instructions, it understands that static binding should be used, while the rest are Use dynamic binding!

3. What bindings are used for overriding and overloading?
Answer: Obviously, rewriting uses dynamic binding, while overloading, the difference between multiple functions is the parameter list, so static binding can be used between them.

4. Understand the principle of dynamic binding and static binding, what enlightenment does it have for you to write code?
Answer: It can be found that if static binding is used, the loading process of the class will be slower, and the subsequent calls will become very fast; and if dynamic binding is used, it needs to be parsed at runtime, which will slow down the program. running speed. Therefore, I think that modifiers such as final can be appropriately used in the code to improve the speed of the program runtime. Of course, too frequent use will also bring about disadvantages such as poor program scalability and long loading time. It is still necessary to trade-off according to the actual situation!

5. You are talking about methods before, so do you know whether variables are statically linked or dynamically linked?
Answer: Let me talk about the answer first. Variables are statically linked. This is the problem that bothered me when I wrote the program mentioned at the beginning, and it is because of this that I thought of learning static binding and dynamic binding. Next, let the code do the talking.
Let 's first look at a very strange phenomenon:
write picture description here
write picture description here
write picture description here
the output of the above code is as follows:
write picture description here
we find that when we directly access the attribute value, the parent class is accessed; and the access method, the subclass is accessed. This caused me great trouble at the time. In fact, this phenomenon can be answered by the knowledge of dynamic binding and static binding, that is: the attribute adopts static binding! The sayHello() method uses dynamic binding! It is for this reason that when you declare a as type A, the value is already bound to the value of class A during the compilation phase, and for sayHello(), it adopts dynamic binding, so at runtime , find that the actual type is A1, and naturally run the sayHello() of A1.

Based on the fact that properties are statically bound, it is easy to explain: in inheritance, properties can only be hidden, while methods can be overridden or hidden (static methods are hidden).
Overriding means that you treat the subclass as the parent class, and the access is still the subclass; while hiding, you treat the subclass as the parent class, and the access is the parent class.
The above code is slightly modified as follows:
write picture description here
write picture description here
write picture description here
write picture description here
We use the int value in the subclass A1 to override the String value of the parent class, and rewrite (override) the sayHello() method, and the output is the same as what we said before. .

6. Excuse me, if there is an int value in the parent class, you can define a boolean value in the subclass, but if there is a public int get() in the parent class, you cannot define public boolean get() in the subclass ). why is that?
Answer: According to the analysis in 5, since the variable is statically bound and hidden, the subclass can use the same variable name as the parent class variable completely freely, and use different modifiers, the static binding will ensure correct sex. For methods, subclasses will inherit and use dynamic binding (overriding). If you have both public int get() and public boolean get(), when you call get(), how do you know to call Which one? So this is not allowed!

Supplement (2018.5.4) : The above answer explains why overloading or rewriting is not allowed through different return value types from the perspective of the underlying implementation. When reading the book "Thinking in java" today, I saw the design level Answer: If you allow overloading or rewriting through different return values, if you use the corresponding type to receive the return value on the left side when calling a function, you can still tell which function is called, as follows:

int say(){
    return 1;
}
String say(){
    return "hello";
}
int x=say();
String y=say();

However, in some cases, we may just want to execute the function and not care about the return value. In this case, we may write code like this:

int say(){
    return 1;
}
String say(){
    return "hello";
}
say();

When this happens, there is no way to tell which say() should be called, so overloading or overriding with a different return type is not allowed.

7. By learning the principles of static binding and dynamic binding, you should also be able to explain exactly why you declare as which class, you can only execute the methods in this class (because the constant pool is resolved according to your declaration. The method table of the type does it, not according to the actual type!), and, if the subclass does not override it, the method of the superclass is executed (because of the inheritance of the method table!).

8. A piece of code to deepen your understanding:
write picture description here
write picture description here
This result will be mistaken if you are not careful, and it is easy to think that the output should be Son-s1() para-char. But if you think about it carefully, there is no function that receives char parameters in the parent class. How does the compilation pass? It turned out that the compiler made a concession because it could not find char, because char can be implicitly converted to int, so the compiler found such a "makeshift method", so that when the constant pool is parsed, it becomes The method with the parameter int is called, and at runtime, the subclass does not override the method with the parameter int, so the parent class is called!

9. A summary of dynamic binding and static binding:
write picture description here
(Note: This picture comes from Zhihu)

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325324950&siteId=291194637