class file loading and initialization process

Source: Internet
Author: User
Tags constant

This blog post describes the various stages of the bytecode file loading process ...

The focus needs to be on what the JVM needs to do at each stage ...


Overview Global---- class files are loaded through various stages:

In Java application development, only the class type that is loaded by the Java Virtual machine can be used in the program. As long as the generated bytecode conforms to the instruction set and file format of the Java Virtual machine, it can be run on the JVM, which provides the conditions for the cross-platform of Java.

The loading process of bytecode files: loading, connecting (including three steps: Verifying readiness parsing), initialization, as shown in the figure


-------------------------------------------------------------------------------------------------

conditions for class loading:

The Java virtual machine does not load the class type unconditionally.

Java Virtual Machine Rules: A class or interface must be initialized when it is first used .

use here refers to active use, active use of the following situations: When creating an instance of a class, such as the use of the new keyword, or by reflection, cloning, deserialization way. When a static method of a class is called, that is, when a bytecode invokestatic instruction is used when a static field of a class or interface is used (except for the final constant, in which case only the class is loaded and not initialized). Even with getstatic or putstatic instructions (you can use Jclasslib software to view the generated bytecode files) when you initialize a subclass by using the methods in the Java.lang.reflect package to reflect the class's methods, you must first initialize the parent class as the starting virtual machine, The class that contains the Main method

In addition to the above situation belongs to the active use, other conditions are passive use, passive use will not cause the initialization of the class, but loaded the class but not initialized.

Example 1: Active use (this is a three class file instead of one, here for convenience to write together. Say a bit more: Because a class file can have only one public class and file name, the rest of the class modifier can only be non-pubic)

public class parent{

static{

System.out.println ("Parent init");

}

} public

class child{

static{

System.out.println ("Child init");

}

} public

class initmain{public

static void Main (string[] args) {child

c = new Child ();

}

}

The above declares 3 classes: The parent child Initmain,child class is a subclass of the parent class. If the parent class is initialized, the static block will be executed, and the "Parent init" will be printed, and if the child class is initialized, "child init" will be printed. (class is loaded before initialization, so after executing a static block of code (<cinit>), the class is already loaded)

Executes the initmain with the result:

Parent init child 

Init

The system first loads the parent class and then loads the child class.

Conforms to the two conditions in the active load: Creating an instance of the class with the new keyword loads the related class, and the parent class must be initialized when the child class is initialized.

Example 2: Passive loading

public class parent{

static{

System.out.println ("Parent init");

public static int v = 100;  static field

} public

class child extends parent{

static{

System.out.println ("Child init");

}

} public

class userparent{public

static void Main (string[] args) {

System.out.println (CHILD.V)  ;

}

}
There is a static variable V in the parent, and in Userparent, its subclass child is used to invoke the variable in the parent class.

Run code:

Parent init

100

Although the subclass object was accessed directly in Userparent, the child subclass was not initialized, only the child class was loaded, only the parent class was initialized. So when referencing a field, only the class that directly defines the field before it is initialized .

Note: Although the child class is not initialized, the child class is now loaded by the system, but not into the initialization phase.

You can run this code with the-xx:+thraceclassloading parameter, view the log, and see that the child class is actually loaded, but the initialization is not

Example 3: Referencing the final constant

public class finalfieldclass{public

static final String conststring = "CONST";

static{

System.out.println ("Finalfieldclass init");

}

} public

class usefinalfield{public

static void Main (string[] args) {

System.out.println (Final  fieldclass.conststring);

}

}

Run code: CONST

The Finalfieldclass class is not initialized because its constant field conststring is referenced because the final constant is properly optimized for its immutability when the class file is generated. After verifying that the bytecode file is correct, the constant is initialized to the specified value during the preparation phase.

To parse the class file generated by the Usefinalfield classes, you can see that the bytecode of the main function is:

In the position of byte code offset 3, the constant pool 22nd item is put into the stack via IDC, and the constant pool 22nd item in this class file is:

#22 = String #23//const

#23 = UTF8 CONST

From This we can see that In the compiled Usefinalfield.class, the Finalfieldclass class is not referenced, but the final constant field in the Finalfieldclass class is stored directly in its own constant pool, so the Finalfiledclass class is naturally not loaded. (Javac at compile time, the constant is directly implanted into the target class, no longer using the referenced class) through the Capture class load log (part of the log) can be seen: (and did not load the Finalfiledclass class log)

Note : Classes that are not present in the code are bound to be loaded or initialized, and if they do not conform to the conditions of active use, the class will not be loaded or further initialized.


The entire process of class loading

1) Load class: in the first stage of class loading.

When the class is loaded, the JVM must complete: the binary data stream of the class is obtained by the full name of the class and the binary flow of the parsing class is the data structure within the method area, that is, the class file is placed in the method area to create an instance of the Java.lang.Class class, representing the type

2) Connection

Validating bytecode files: when the class is loaded into the system, the connection operation begins, and validation is the first step in the connection.

The main purpose is to ensure that the loaded bytecode is in compliance with the code.

Verify the steps as shown in the figure:

Preparation Phase

When a class is validated, the virtual machine goes into the prep phase. The preparation stage is to formally allocate memory for class variables (static modified variables) and set class variable initial values, which are allocated in the method area. This time the memory allocation is only a class variable, excluding instance variables, the instance variables will be allocated on the heap along with the object when the object is instantiated. Setting the initial value for a class variable is a value of 0 that is set to its data type.

For example, public static int num = 12; The NUM variable will be assigned a value of 0 at this time.

Java Virtual machines default initial values for various types of variables such as tables:

Type Default Initial value
Int 0
Long 0L
Short (short) 0
Char \u0000
Boolean False
Reference Null
Float 0f
Double 0f

Note: Java does not support Boolean types, and for Boolean types, the internal implementation is int, because the default value of int is 0, so the default value of Boolean is False

If a field in a class is a constant, the constant field is also appended with the correct value in the preparation phase, which is the behavior of the Java Virtual machine, which is the initialization of the variable. During the preparation phase, no Java code will be executed.


Parsing Classes

After the preparation phase is complete, it enters the parsing phase.

The task of the parsing phase is to convert the symbolic references of classes, interfaces, fields, and methods to direct references.

A symbolic reference is a reference to some literal quantity. It is easy to understand that in class files, a large number of symbolic references are made through a constant pool.

You can use the Jclasslib software to view the structure of the class file::

The following is a simple function call to explain how the symbolic reference works ...

For example: System.out.println ();

Generated bytecode directive: invokevirtual #24 <java/io/PrintStream.println>

The constant pool 24th item is used here to view and analyze the constant pool, and you can view the structure as shown in the figure:


Chang 24th is used by invokevirtual, and along Constant_methodref #24的引用关系继续在常量池中查找, all references to class and Nameandtype types are string-based, so It can be assumed that invokevirtual's function calls are expressed by literal reference descriptions, which are symbolic references.

But only symbolic references are not enough, and when the println () method is called, the system needs to know exactly where the method is. The Java Virtual opportunity prepares a method table for each class, lists all its methods in the table, and when it is necessary to call a method of a class, just know that the method is offset in the table. By parsing an operation, a symbolic reference can be transformed into the location of the method table in the class of the target method, so that the method is called successfully.

Therefore, the purpose of parsing is to turn a symbolic reference into a direct reference, that is, to get the class or field, the method in memory pointers or offsets. If a direct reference exists, there must be a class, method, or field in the system, but there is only a symbolic reference, and it is not certain that the object must exist in the system.


3) class initialization

If the previous steps do not have a problem, the presentation class can be loaded into the system smoothly. At this point, the Java bytecode will start executing .

An important work in the initialization phase is the initialization method <clinit> () of the execution class. Its characteristics:

The <clinit> () method is generated automatically by the compiler, which is produced by the assignment statement of the class static member and the static statement block . The order that the compiler collects is determined by the order in which the statements appear in the source file, and only the class variables defined before the static statement block can be accessed in the static statement block, and the class variables defined after them can only be assigned values and cannot be accessed.  For example: static{num = 5; Assignment operation, which is legal,}

static int num = 12;

------------------------------------------------------------

static{

SYSTEM.OUT.PRINTLN (num); Illegal access

}

static int num = 12;

For example:

public class simplestatic{public

static int id = 1;

public static int number;

static{number

= 4;

}

}

The Java compiler generates the following <clinit&gt for this piece of code:

0 iconst_1
1 putstatic #2 <Demo.id>
4 Iconst_4
5 putstatic #3 <Demo.number>
8 return

<clinit> function, a static assignment statement in the Simplestatic class and a static statement block are consolidated

Change the JVM Instruction code representation: The ID and number two member variables are assigned

The <clinit> () method differs from the constructor function <init> () method of the class, and it does not need to display the <clinit> () method of the calling parent class, and the virtual opportunity guarantees that the child class's <clinit> () method executes before the The <clinit> () method of the parent class has been executed. Therefore, the static statement block of the parent class is executed before the static statement block of the child class.

public class Childstatic extends simplestatic
{
static{number
= 2;
} public
static void Main (string[] args) {
System.out.println (number);
}
}

Run code:

2

Indicates that the <clinit> of the parent class is always called before subclass <clinit>.

Note : TheJava compiler does not generate <clinit> initialization functions for all classes, and if a class has neither a class variable assignment statement nor a static statement block, the resulting <clinit> function should be empty. Therefore, the compiler does not insert the <clinit> function for the class

For example:

public class staticfinalclass{

public static final int i=1;

public static final int j=2;

}

Because Staticfinalclass has only a final constant, and the final constant is assigned in the preparation phase, not in the initialization phase, there is nothing to do with the Staticfinalclass class,<clinit>, so The function does not exist in the resulting class file.

The virtual machine guarantees that the <clinit> () method of a class is correctly locking and synchronized in a multithreaded environment, and if multiple threads initialize a class at the same time, only one thread executes the <clinit> () method of the class, and the other threads are blocked. Until the specified thread finishes executing the <clinit> () method.


--------------------------------------------------------------------------------------------------------------- -----------------------------------

Take a look at the object initialization process, including the sequence of member variables and constructor invocations, the order of precedence between the subclass constructor and the parent class, and so on. This process is demonstrated directly through bytecode file directives :

Edit several classes, including a subclass of a parent class, where both the subclass and the parent class contain member variables, non-static code blocks, constructor functions, and static and static variables described earlier:

Package com.classextends;
public class Fuzidemo {public
	static void Main (string[] args) {
		new Ziclass ();//test class, create sub-class object
	}
}

Class Fuclass {
	int fuower = +;  Member variable one
	static{
		System.out.println ("Fu clinit ()");  Static code block
	} static
	int num = 22;//static variable
	{				//non-static code block
		funame = "Tempvalue";    
		System.out.println (fuower);
		int c = ALL;
	}
	String funame = "Dali"; Member variable two
	fuclass () {		//Parent class constructor
		System.out.println ("Fu init ()");
		Fuower = +;
	}
}

Class Ziclass extends Fuclass {
	int ziower =;    Member variable one
	static{		    //Static code block
		System.out.println ("Zi clinit ()");
	}
	static int num = 2; Static variable
	{		    //non-static code block
		ziname = "Tempvalue";
		System.out.println (ziower);
		int c = ALL;   Local variable
	}
	String ziname = "urocle";//member Variable two
	
	ziclass () {  //Sub-class constructor
		ziower =;
		System.out.println ("Zi init ()");
	}
}


Analysis:

the loading and initialization of a class

First Fuzidemo this test class to load, and then execute the main instruction will be new subclass object, it is necessary to load the sub-class bytecode file, but will find that subclasses have a direct inheritance class Fuclass, so will first load Fuclass bytecode file, then initialize the parent class, Executes the <clinit> method of the Fuclass class: Executes the output statement and assigns a value to the static member whose bytecode instruction is:

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.