Home > Java > javaTutorial > body text

Let you understand the static keyword in Java at once

醉折花枝作酒筹
Release: 2021-08-04 17:49:46
forward
2097 people have browsed it

I believe that many students have encountered this kind of question. They may have checked the information and then forgotten it. If they encounter it again, they still cannot answer it correctly. Next, through 4 steps, I will take you to disassemble the execution sequence of this code and summarize the rules.

The opening question is to examine the order of code execution:

public class Parent {
    static {
        System.out.println("Parent static initial block");
    }

    {
        System.out.println("Parent initial block");
    }

    public Parent() {
        System.out.println("Parent constructor block");

    }
}

public class Child extends Parent {
    static {
        System.out.println("Child static initial block");
    }

    {
        System.out.println("Child initial block");
    }
    
    private Hobby hobby = new Hobby();

    public Child() {
        System.out.println("Child constructor block");
    }
}

public class Hobby {
    static{
        System.out.println("Hobby static initial block");
    }

    public Hobby() {
        System.out.println("hobby constructor block");
    }
}
Copy after login

What does the above code output when new Child() is executed?

I believe that many students have encountered this kind of problem. They may have checked the information and then forgotten it. If they encounter it again, they still cannot answer it correctly. Next, the class representative will take you through 4 steps to dismantle the execution sequence of this code and summarize the rules.

1. What does the compiler optimize?

The following two pieces of code compare the changes before and after compilation:

Child.java before compilation

public class Child extends Parent {
    static {
        System.out.println("Child static initial block");
    }
    {
        System.out.println("Child initial block");
    }
    
    private Hobby hobby = new Hobby();
    
    public Child() {
        System.out.println("Child constructor block");
    }
}
Copy after login

Child.class after compilation

public class Child extends Parent {
    private Hobby hobby;

    public Child() {
        System.out.println("Child initial block");
        this.hobby = new Hobby();
        System.out.println("Child constructor block");
    }

    static {
        System.out.println("Child static initial block");
    }
}
Copy after login

Passed From the comparison, we can see that the compiler moves the assignment operations of the initialization block and instance fields to before the constructor code, and retains the order of related codes. In fact, if there are multiple constructors, the initialization code will be copied and moved over.

Based on this, the first priority order can be drawn:

  • Initialization code > Constructor code

2. What does static do?

The loading process of a class can be roughly divided into three stages: Loading-> Link-> Initialization

The initialization stage can be triggered by 8 situations Zhou Zhiming》P359 "8 types of triggering class initialization Situation ") trigger:

  • When using the new keyword to instantiate an object

  • Read or set a static field of a type (constant" )

  • Calling a static method of a type

  • When using reflection to call a class

  • When initializing a class, if it is found that the parent class has not been initialized, the parent class initialization will be triggered first.

  • When the virtual machine starts, the main class (including main() will be initialized first. ) method)

  • When the MethodHandle instance is called for the first time, initialize the class where the method pointed to by the MethodHandle is located.

  • If in the interface A default method (default modified interface method) is defined, and the implementation class of the interface is initialized, then the interface must be initialized before it

Items 2 and 3 are Triggered by static code.

In fact, the initialization phase is the process of executing the class constructor<clinit> method. This method is automatically generated by the compiler, and it collects the assignment actions and static modifications of all class variables modified by static. statement block (static{} block), and retain the order in which these codes appear.

According to item 5, the JVM will ensure that before the subclass's <clinit> method is executed, the parent class's <clinit> The method has been executed.

To summarize: accessing class variables or static methods will trigger the initialization of the class, and the initialization of the class is to execute <clinit>, that is, to execute the static modified assignment action and static{} block, and the JVM guarantees that the parent class initialization is performed first, and then the subclass initialization is performed.

This leads to the second priority order:

  • static code of the parent class> Static code of subclasses

3.static code is only executed once

We all know that static code (except static methods) is only executed once.

You have Never thought about how this mechanism is guaranteed?

The answer is: Parental delegation model.

The parental delegation model of JDK8 and before is:

Application class loading Device → Extension Class Loader → Start Class Loader

Classes written in normal development are loaded by the application class loader by default, and it will be delegated to its parent class: the extension class loader. The extension class loader in turn delegates to its parent class: the startup class loader. Only when the parent class loader reports that it cannot complete the loading request, the child loader will try to complete the loading by itself. This process is parent delegation. The parent-child relationship between the three is not achieved through inheritance, but through the combination mode.

The implementation of this process is also very simple. The key implementation code is shown below:

protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
{
    // 首先检查该类是否被加载过
    // 如果加载过,直接返回该类
    Class<?> c = findLoadedClass(name);
    if (c == null) {
        try {
            if (parent != null) {
                c = parent.loadClass(name, false);
            } else {
                c = findBootstrapClassOrNull(name);
            }
        } catch (ClassNotFoundException e) {
            // 如果父类抛出ClassNotFoundException
            // 说明父类无法完成加载请求
        }

        if (c == null) {
            // 如果父类无法加载,转由子类加载
            c = findClass(name);
        }
    }
    if (resolve) {
        resolveClass(c);
    }
    return c;
}
Copy after login

With the comments, I believe it is easy for everyone to understand.

It can be seen from the code delegated by parents that under the same class loader, a class can only be loaded once, which limits it to only be initialized once. Therefore, the static code in the class (except static methods) is only executed once when the class is initialized

4. <init> and <clinit>

As mentioned earlier, the compiler automatically generates Class constructor: <clinit> method, it will collect the assignment actions and static statement blocks (static{} blocks) of all static-modified class variables and retain the order of appearance of the code. It will be executed when the class is initialized

Correspondingly, the compiler will also generate an <init> method, which will collect the assignment actions of the instance fields, the code in the initialization statement block ({} block) and the constructor (Constructor), and retain the order of appearance of the code. , it will be executed after the new instruction

So, when we new a class, if the JVM has not loaded the class, it will be initialized first and then instantiated.

At this point, the third priority rule is ready to come out:

  • Static code (static{} block, static field assignment statement) > Initialization code ({} block, instance field assignment statement)

5. Regular practice

Combine the three previous rules and summarize the following two:

1. Static code (static{} block, static field assignment statement) > Initialization code ({} block, instance field assignment statement) > Constructor code

2. Static code of the parent class> Static code of the subclass

According to the previous summary, the initialization code and constructor code are collected by the compiler<init> , the static code is collected into <clinit>, so the above rules are merged again:

Parent class<clinit> > Subclass<clinit> > Parent class <init> > Subclass <init>

Corresponds to the question at the beginning, let’s practice it:

When executing new Child(), the new keyword triggers the initialization of the Child class. When the JVM finds that it has a parent class, it first initializes the Parent class, starts executing the <clinit> method of the Parent class, and then executes the Child class. The <clinit> method (remember what is collected in <clinit>?).

Then start instantiating an object of the Child class. At this time, we are ready to execute the <init> method of Child. We find that it has a parent class. We will execute the <init> method of the parent class first, and then execute the child class. of <init> (remember what is collected in <init>?).

I believe that after reading this, you already have the answer to the opening question. You might as well hand-write the output sequence first, and then write the code to verify it yourself.

Conclusion

static is often used in daily development. Every time I write, there are always two questions in my mind. Why should I use static? Is it okay without it?

As can be seen from this article, the application of static is far more than just class variables and static methods. In the classic singleton pattern, you will see various uses of static. The next article will write about how to write the singleton pattern in a fancy way.

The above is the detailed content of Let you understand the static keyword in Java at once. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:segmentfault.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!