Understand static code blocks and construct code blocks from the perspective of virtual machines.

Source: Internet
Author: User

Understand static code blocks and construct code blocks from the perspective of virtual machines.

A static code block is a code block modified with the static keyword. A code block is executed only once before the class constructs a code block or constructor. Constructing a code block is simply a code block composed of curly braces. It is characterized by code blocks that run before class constructor and are called every time an object is instantiated. This blog describes static code blocks and constructed code blocks from the perspective of virtual machines to deepen understanding.

First, we need to know that when you compile the. java file into a. class file, if there is a static code block, it will insert a section in the. class file called<clinit>Instead of static code blocks. If a constructor code block exists, it inserts a section in each constructor called<init>Instead of constructing code blocks

Second, we need to understand the class lifecycle (for example ),<clinit>The function is called at the initialization level.And only once in the initialization phase.<clinit>The function is called only once, which is why the static code block is called only once when the class is used. In other cases, the static code block is not called.

Let's use javap disassembly.

Public class Student {static {System. out. println ("first constructed code block");} static {System. out. println ("second constructed code block");} {System. out. println ("first constructed code block");} {System. out. println ("second constructed code block");} public Student () {System. out. println ("default constructor");} public Student (String name, int age) {System. out. println ("Custom constructor"); this. name = name; this. age = age;} private String name = "Clive"; private static int age = 17; private final static String COUNTRY = "CN"; private final String SCHOOL = "JXAU ";} /* E: \ eclipseWork \ Test \ bin \ test> javap-c Student warning: the binary file Student contains test. studentCompiled from "Student. java "public class test. student {static {}; Code: 0: getstatic #19 // Field java/lang/System. out: Ljava/io/PrintStream; 3: ldc #25 // String the first construction code block 5: invokevirtual #27 // Method java/io/PrintStream. println :( Ljava/lang/String;) V 8: getstatic #19 // Field java/lang/System. out: Ljava/io/PrintStream; 11: ldc #33 // String second construction code block 13: invokevirtual #27 // Method java/io/PrintStream. println :( Ljava/lang/String;) V 16: bipush 17 18: putstatic #35 // Field age: I 21: return public test. student (); Code: 0: aload_0 1: invokespecial #40 // Method java/lang/Object. "<init>" :() V 4: getstatic #19 // Field java/lang/System. out: Ljava/io/PrintStream; 7: ldc #25 // String the first construction code block 9: invokevirtual #27 // Method java/io/PrintStream. println :( Ljava/lang/String;) V 12: getstatic #19 // Field java/lang/System. out: Ljava/io/PrintStream; 15: ldc #33 // String second Construction Code Block 17: invokevirtual #27 // Method java/io/PrintStream. println :( Ljava/lang/String;) V 20: aload_0 21: ldc #42 // String Clive 23: putfield #44 // Field name: Ljava/lang/String; 26: aload_0 27: ldc #14 // String JXAU 29: putfield #46 // Field SCHOOL: Ljava/lang/String; 32: getstatic #19 // Field java/lang/System. out: Ljava/io/PrintStream; 35: ldc #48 // String default constructor 37: invokevirtual #27 // Method java/io/PrintStream. println :( Ljava/lang/String;) V 40: return public test. student (java. lang. string, int); Code: 0: aload_0 1: invokespecial #40 // Method java/lang/Object. "<init>" :() V 4: getstatic #19 // Field java/lang/System. out: Ljava/io/PrintStream; 7: ldc #25 // String the first construction code block 9: invokevirtual #27 // Method java/io/PrintStream. println :( Ljava/lang/String;) V 12: getstatic #19 // Field java/lang/System. out: Ljava/io/PrintStream; 15: ldc #33 // String second Construction Code Block 17: invokevirtual #27 // Method java/io/PrintStream. println :( Ljava/lang/String;) V 20: aload_0 21: ldc #42 // String Clive 23: putfield #44 // Field name: Ljava/lang/String; 26: aload_0 27: ldc #14 // String JXAU 29: putfield #46 // Field SCHOOL: Ljava/lang/String; 32: getstatic #19 // Field java/lang/System. out: Ljava/io/PrintStream; 35: ldc #53 // String custom constructor 37: invokevirtual #27 // Method java/io/PrintStream. println :( Ljava/lang/String;) V 40: aload_0 41: aload_1 42: putfield #44 // Field name: Ljava/lang/String; 45: iload_2 46: putstatic #35 // Field age: I 49: return }*/

Why? Say yes<clinit>What about functions? This is because<clinit>A function cannot be called by java. It can only be called directly by JVM as part of the class loading process. For details, see references at the end of this article. JVM "beautifies the function" and decomassembles the code.static {};That is<clinit>Static code block. Slave<clinit>Function, we can get some information.

  • Multiple Static code blocks are eventually merged into one<clinit>Function for JVM call

There are two static code blocks in the source code, and the code produced by disassembly only has one<clinit>

  • The assignment operation for the static data field is<clinit>Completed in Function

The data field age is a static data field (private static int age = 17;), corresponding<clinit>The offset of 18 in the function.

18: putstatic #28 // Field age: I

From the constructor, we can obtain some information related to the constructor code block.

  • The value assignment operation of final static data field is not<clinit>Completed in Function

COUNTRY in the data domain uses not only static keyword modification, but also final modification. However, there is no related value assignment instruction in the disassembly code, because when a data domain uses final modification, the assignment operation has been completed in the preparation phase, and so has the data domain SCHOOL.

  • Every time the constructor runs, the function is called.

From the disassembly code, we can see that a call is inserted in both the default constructor and custom constructor.<init>Function bytecode command, invokespecial #33 // Method java/lang/Object. "" :() V that is why the constructed code block has this feature: each time an object is instantiated, the static code block will be executed and executed before the constructor.

  • Multiple constructor code blocks are also integrated into a function.

There are two construction code blocks in the source code, and the constructor only calls one<init>Function. It can be seen that the virtual machine quickly integrates the constructed code.

  • The assignment operation of common data domains is completed in the constructor.

The data domain name is a common data domain (private String name = "Clive ";). The value assignment operation corresponds to the bytecode instruction with the offset of 21 in the default constructor. In the custom constructor, the corresponding bytecode offset is also 21.

Static code block and <clinit>To construct the relationship between the code block and <init>Relationship

Based on the disassembly code above, we know that<clinit>A simple function as a static code block is a wrong idea, because<clinit>The function also includes assigning values to static data fields. Therefore,<clinit>The relationship between a function and a static code block should be inclusive. Construct code blocks and<init>The same is true.

In the inheritance relationship

When a static code block exists in the parent class, the static code block of the subclass does not display or implicitly call the instruction of the static code block of the parent class, but the virtual opportunity is guaranteed in<clinit>Before the function is run<clinit>The operation has been completed.

Not all classes generate functions.

If there is no static code block in the class, and there is no assignment operation for the static data field, no output will be made.<clinit>Function

Public class Student {System. out. println ("first constructed code block");} {System. out. println ("second constructed code block");} public Student () {System. out. println ("default constructor");} public Student (String name, int age) {System. out. println ("Custom constructor"); this. name = name;} private String name = "Clive"; private final static String COUNTRY = "CN"; private final String SCHOOL = "JXAU" ;}/ * E: \ eclipseWork \ Test \ bin \ test> javap-c Student warning: the binary file Student contains test. studentCompiled from "Student. java "public class test. student {public test. student (); Code: 0: aload_0 1: invokespecial #17 // Method java/lang/Object. "<init>" :() V 4: getstatic #19 // Field java/lang/System. out: Ljava/io/PrintStream; 7: ldc #25 // String the first construction code block 9: invokevirtual #27 // Method java/io/PrintStream. println :( Ljava/lang/String;) V 12: getstatic #19 // Field java/lang/System. out: Ljava/io/PrintStream; 15: ldc #33 // String second Construction Code Block 17: invokevirtual #27 // Method java/io/PrintStream. println :( Ljava/lang/String;) V 20: aload_0 21: ldc #35 // String Clive 23: putfield #37 // Field name: Ljava/lang/String; 26: aload_0 27: ldc #12 // String JXAU 29: putfield #39 // Field SCHOOL: Ljava/lang/String; 32: getstatic #19 // Field java/lang/System. out: Ljava/io/PrintStream; 35: ldc #41 // String default constructor 37: invokevirtual #27 // Method java/io/PrintStream. println :( Ljava/lang/String;) V 40: return public test. student (java. lang. string, int); Code: 0: aload_0 1: invokespecial #17 // Method java/lang/Object. "<init>" :() V 4: getstatic #19 // Field java/lang/System. out: Ljava/io/PrintStream; 7: ldc #25 // String the first construction code block 9: invokevirtual #27 // Method java/io/PrintStream. println :( Ljava/lang/String;) V 12: getstatic #19 // Field java/lang/System. out: Ljava/io/PrintStream; 15: ldc #33 // String second Construction Code Block 17: invokevirtual #27 // Method java/io/PrintStream. println :( Ljava/lang/String;) V 20: aload_0 21: ldc #35 // String Clive 23: putfield #37 // Field name: Ljava/lang/String; 26: aload_0 27: ldc #12 // String JXAU 29: putfield #39 // Field SCHOOL: Ljava/lang/String; 32: getstatic #19 // Field java/lang/System. out: Ljava/io/PrintStream; 35: ldc #48 // String custom constructor 37: invokevirtual #27 // Method java/io/PrintStream. println :( Ljava/lang/String;) V 40: aload_0 41: aload_1 42: putfield #37 // Field name: Ljava/lang/String; 45: return }*/
Delete the static code block and static data field in Student. The final disassembly Code does not contain the <clinit> function.
The interface will also generate Functions

The interface XXX cannot define an initializer is not allowed in The interface, but its data fields are static by default, so<clinit>Function. In addition, only when this interface is actually used<clinit>Function. That is to say, two interfaces A, B, and A are the parent interfaces of B. When interface B is used<clinit>Functions are not run. Only the interface is actually used.<clinit>Function to run, such as using the data domain in the interface. In addition, I don't want to lie to you. This is the case in the book. However, I used the disassembly code generated by javap to find that the code was not generated.<clinit>Instead, a default constructor is generated, which assigns values to the data domains. I think the JDK version is different :)

Public class Speak {int COUNT = 2;}/* E: \ eclipseWork \ Test \ bin \ test> javap-c Speak warning: the binary file Speak contains test. speakCompiled from "Speak. java "public class test. speak {int COUNT; public test. speak (); Code: 0: aload_0 1: invokespecial #10 // Method java/lang/Object. "<init>" :() V 4: aload_0 5: iconst_2 6: putfield #12 // Field COUNT: I 9: return }*/

 

 
<clinit>Function thread security 
To ensure thread security, only one thread is allowed to access the virtual machine when the multi-thread view initializes the same class.<clinit>Function, other threads must wait. When<clinit>When function execution is complete, other threads discover<clinit>If the function has been executed, it will not be executed.<clinit>Function. If the mutex synchronization operation is completed using a lock, a lock may lead to a deadlock, as shown below.
 
Package test; import java. SQL. SQLException; import java. util. concurrent. executorService; import java. util. concurrent. executors; public class Test {public static void main (String [] args) throws ClassNotFoundException, SQLException {// initialize class when imitating multithreading // ExecutorService executor = Executors. newCachedThreadPool (); executor.exe cute (new Task ("test. A "); executor.exe cute (new Task (" test. B "); executor. shutdown (); System. out. println ("over");} private static class Task implements Runnable {private String className; public Task (String className) {this. className = className;} public void run () {try {Class. forName (className);} catch (ClassNotFoundException e) {e. printStackTrace ();}}}}
 
Package test; public class A {static {System. out. println ("enter static block of A"); try {Thread. sleep (1, 5000); Class. forName ("test. B "); // initialize B} catch (ClassNotFoundException e) {e. printStackTrace ();} catch (InterruptedException e) {e. printStackTrace ();} System. out. println ("out static block of ");}}
Package test; public class B {static {System. out. println ("enter static block of B"); try {Thread. sleep (1, 5000); Class. forName ("test. A "); // initialize A} catch (ClassNotFoundException e) {e. printStackTrace ();} catch (InterruptedException e) {e. printStackTrace ();} System. out. println ("out static block of B ");}}

The above code simulates the deadlock caused by class initialization in a multi-threaded environment. When A thread enters<clinit>Function, according to the Code, it needs to initialize class B, and Class B's<clinit>The function is already occupied by another thread and Class A needs to be initialized. In this way, both parties hold their own resources and request other resources, which will naturally lead to deadlocks.

 

Summary

<Clinit> the function contains the code in the static code block. It runs only once during class initialization. <Init> contains the code in the constructor code block. It runs before the constructor when the object is instantiated.

Reference

1. deep understanding of Java Virtual Machine

2. Actual Java Virtual Machine

3. Forum: http://hllvm.group.iteye.com/group/topic/35224

 



Related Article

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.