To the chase

In order to avoid unnecessary waste of time, the article mainly revolves around two points:

1. Why is overloading based on static and not dynamic types?

2. Symbolic references to the corresponding methods are invoked through dynamic/static dispatching.

If you have a deeper understanding of these two problems, this article is worth not reading, haha ~

In the second half of this article, we will talk about symbolic references at the bytecode level. If you are not familiar with the Class file structure, you can choose to watch or read this article, dynamic Proxy Trilogy: From dynamic proxy, see the Class file structure definition

Albert Einstein: “If you cannot explain something simply, you do not really understand it.”

The difference between a=a+b and a+=b

Reload/rewrite, dynamic/static dispatch? (Revised)

Internal anonymous classes use external variables. Why add final

[short essay velocity -4] Whether the new subclass instantiates the parent class

Introduction to Multithreaded programming: Processes, threads, thread safety

primers

Little A: MDove, I have A problem that I can’t figure out.

MDove: Normal, after all your IQ 1+1 equals 2 for no reason.

Little A: Why is 1+1 equal to 2?

MDove:… Talk about your problems.

The confusion of overloading

Little A: Well, when I was learning about polymorphism, I overloaded and overwrote, and I got A little confused. I wrote a reloading and rewriting demo myself…

public class MethodMain {
    public static void main(String[] args) {
        MethodMain main = new MethodMain();
        Language language = new Language();
        Language java = new Java();
        / / overloaded
        main.sayHi(language);
        main.sayHi(java);
        / / rewrite
        language.sayHi();
        java.sayHi();
    }

    private void sayHi(Java java) {
        System.out.println("Hi Java");
    }
    private void sayHi(Language language) {
        System.out.println("Im Language"); }}public class Java extends Language {
    @Override
    public void sayHi(a) {
        System.out.println("Hi,Im Java"); }}public class Language {
    public void sayHi(a) {
        System.out.println("Hi,Im Language"); }}Copy the code

Little A: There is no doubt about the result of rewriting. But why does an overloaded demo run like this? I think it should be one Im Language and one Hi Java. After all, when I call a method, I pass an instantiated type of Java and an Languae. Why not have one match parameter of Java and one match parameter of Language?

Overloaded method version selection is based on: static variable

MDove: That’s the question. Actually, I had the same question at first. A A = new B(). The A of A is called static type, and B is called dynamic type/actual type.

MDove: Now that this concept is clear, let’s look at R big’s answer. (I’ve extracted the relevant content here, but if you want to know more, you can check out the answers below.)

Why is determining which version of the overload to call only determined by the static type of the parameter passed in, and not by its dynamic type (the actual type of the actual parameter passed in at run time)? The roots are not complicated: it was the norm at the time, and C++ was designed that way, so Java inherited. The advantage of this is that it is simple to design and implement, and method overloading has no additional overhead at runtime… (omitted)… The downside is obvious: flexibility is sacrificed. If the program really needs to do dynamic dispatch based on the actual types of multiple parameters, it’s up to the programmers to do it themselves.

Little A: I didn’t think it was out of such A consideration. So we’re going to reload and rewrite. So many very similar methods. How does the JVM select and invoke specific methods?

MDove: This procedure is a method call, and with this procedure we have to talk about dispatching. There are two types of dispatch: static dispatch and dynamic dispatch. These two methods determine the final execution of a method.

Location of method

Static dispatching

MDove: Little A, do you think there are obvious differences between the two demos? Or go up another level. Is there a difference in business scenarios between overloading and overwriting?

Little A: When you say that, it sounds true! Overloading is messing around in a class; Rewriting is a subclass messing with its parent class.

MDove: Exactly! Let’s summarize:

  • Overloading is the preferred method of choice.
  • Overrides are more about who is actually calling the method.

MDove: In the overloaded demo you wrote above, for Language Language = new Java(); For example: Language is static type, Java is actual type. MethodMain main = new MethodMain(); Same thing, MethodMain main this MethodMain is static, new MethodMain() this is MethodMain is the actual type.

MDove: So, for the JVM, the static type of the argument/and caller is determined at compile time, and therefore the symbolic reference to the method at this step is determined. (This process is called static dispatch.)

Little A: Oh, it turns out that symbolic references are determined at compile time… No, wait!! If it is certain that symbolic references also use the caller’s static type, then overrides also call methods in static types. !!!!!!!!!

MDove: Wow, you are quick on your feet! To answer your question first, overwriting is indeed the same thing as overloading identified symbol references in this process! Let’s take a look at the bytecode in your demo. Here’s just a snippet:

Red is overloading, purple is overwriting

MDove: See, you’re right, the ones marked in purple are the symbolic references that the overridden methods decided on at compile time. They are indeed the same because of static dispatch! The method selection for overloading is determined during this process, but rewriting is special in that it depends on the actual type of the runtime object, so it also requires dynamic dispatch for overloading.

MDove: For static dispatch. Basically, at compile time, you decide which version of the method to call. The ACTUAL types that are generated at run time are therefore of no concern to the JVM. As long as your static type is Guo Degang, even if you new a Wu Yifan out. This line of code can’t be wide and long…

MDove: To summarize, all methods that rely on static types to locate the version of a method execution are called static dispatch.

Little A: Static dispatch I see. Let’s talk about dynamic dispatch! I wonder why the same symbol reference, overrides perform different methods!

Dynamic dispatch

MDove: We all know that overwriting involves whether you call a subclass’s method or a parent’s. That is, the actual type of the caller has an effect on rewriting, so static dispatch alone is not an option in this case, and dynamic dispatch at run time is needed to further determine this.

MDove: This time let’s look at the bytecode situation in the main method:

MDove: Here is a brief explanation of these bytecode instructions:

First purple circle: Perform the symbolic application of constant pool #5 and push it down to position 2 on the operand stack.

The first purple line is the symbol reference for constant pool #5. We can tell that it is a Language type.

First red circle: perform the symbolic application of constant pool #6 and push it down to position 3 on the operand stack.

The first red line is the symbol reference for constant pool #6. We can see that it is a Java type

The second purple circle: remove the variable from operand stack 2 and execute invokevirtual, which is called #9.

The second purple line is the symbol reference for constant pool #9. We can see the language.sayhi () method.

The second red circle: remove the variable from operand stack 3 and perform the invokevirtual execution, which is called #9.

The second red line is the symbol reference for constant pool #9. We can see the language.sayhi () method.

MDove: From the bytecode instructions we can see that everything is the same except for the different types of variables in the operand stack. So the dynamic dispatch feature is in the implementation of Invokevirtual.

MDove: Simply put, when a virtual machine executes invokevirtual, it finds the first element on the top of the operand stack, looks for its actual type, and then finds its symbolic reference. If it doesn’t find one, it works its way up until it finds one. The method call is then dynamically linked to its real memory address.

SayHi () : aload_3 = java.sayhi (); sayHi() : aload_3 = java.sayhi (); sayHi() : aload_3 = java.sayhi (); And that completes our rewrite call.

Small A: Java is so fun. I want to go home and deliver food…

conclusion

In the case of overloading, static typing determines which version of the method to select (which symbolic reference to call) at compile time. The process of locating the execution version of a method by static typing is called static dispatch.

For overwriting, static typing is obviously not an option, so dynamic typing is needed. This process of locating the execution version of a method by dynamic typing is called dynamic dispatch.

The end

I am a fresh graduate, recently and friends maintain a public account, the content is that we in the transition from fresh graduate to the development of this way stepped on the pit, as well as our step by step learning records, if interested in friends can pay attention to it, together with fuel ~