java(1) class loading and initialization

Contents

Class Loader
Dynamic Loading
Link
Initialization
Example
Class Loader

Before understanding the mechanism of Java, you need to understand how classes are loaded in the JVM (Java Virtual Machine), which will play an important role in understanding other mechanisms of java.

After each class is compiled, a Class object is generated and stored in the .class file. The JVM uses the class loader (Class Loader) to load the bytecode file (.class) of the class. The class loader is essentially a class loader chain. , Generally, we only use a native class loader, which only loads trusted classes such as Java API, usually only in the local disk, and these classes are generally enough for us to use. If we need to download a .class bytecode file from a remote network or database, we need to mount an additional class loader.

Generally, class loaders are organized in a tree-like hierarchy, with each loader having a parent class loader. In addition, each class loader supports the proxy mode, that is, it can complete the loading of Java classes by itself, or it can be delegated to other class loaders.

There are two kinds of loading order of the class loader, one is the parent class priority strategy, the other is the own priority strategy, the parent class priority strategy is a more general situation (such as JDK adopts this method), in this strategy Under the above, the class will try to proxy to its parent class loader before loading a Java class, and only try to load it by itself when the parent class loader cannot be found. The strategy of self-priority is opposite to that of parent-class priority. It will first try to load the sub-economy, and when it cannot be found, it will be loaded by the parent class loader. This is more common in web containers (such as tomcat).

Dynamic loading

No matter what class loader is used, classes are dynamically loaded into the JVM when they are used for the first time. This sentence has two meanings:

The Java program is not necessarily fully loaded at runtime. Only when it is found that the class has not been loaded, the .class file of the class is searched locally or remotely and verified and loaded;
when the program creates the first static member of the class The class will be loaded only when the reference of the class (such as static variables, static methods, constructors of the class - the constructor is also static). This feature of Java is called: dynamic loading.
It is necessary to distinguish the difference between loading and initialization. When a .class file of a class is loaded, it does not mean that the Class object is initialized. In fact, the initialization of a class includes 3 steps:

Loading, executed by the class loader, search Bytecode, and create a Class object (just create);
Linking, verify bytecode, allocate storage space for static fields (just allocate, do not initialize the storage space), parse the pairs required for the creation of the class Application of other classes;
initialization (Initialization), first execute the static initialization block static{}, initialize static variables, and execute static methods (such as constructors).
Linking

Java After the class is loaded, the linking step is required. The linking is simply to combine the loaded java binary code into the JVM running state. It includes 3 steps:

Verification. Verification is to ensure the correctness of the binary bytecode in structure. Specifically, the work includes checking the correctness of the type, the correctness of the access attributes (public, private), and checking the final class. Not being inherited, checking static variables for correctness, etc.
Preparation (Preparation), the preparation stage is mainly to create static fields, allocate space, and set default values ​​for these fields. There are two points to note: one is that no code will be executed in the preparation stage, only default values ​​are set, and the other is These default values ​​are assigned in this way, all primitive types are set to 0, such as: float: 0f, int 0, long 0L, boolean: 0 (boolean types are also 0), and other reference types are null.
Resolution (Resolution), the process of parsing is to parse and locate the symbolic references of interfaces, classes, methods, and variables in the class, and parse them into direct references (symbolic references are encodings that use strings to represent the location of a variable or interface, Direct references are addresses translated from symbolic references), and ensure that these classes are found correctly. The parsing process may cause other classes to be loaded. It should be noted that this step is not necessarily required according to different parsing strategies. Some parsing strategies recursively parse all references during parsing. This is early resolution, which requires all references to exist; another strategy is late resolution, which is also the strategy adopted by Oracle's JDK, that is, when the class is only referenced and has not been actually used, it will not be parsed. Only when it is actually used, will the class be loaded and parsed.
Initialization

Note : In "Java Programming Ideas", it is said that the static{} clause is executed when the class is first loaded and executed once (may be a typo or translation error, because the example in this book shows that static is initialized at the first time When executed), "Java Depth Adventures" said that static{} is executed at the first instantiation and executed once, both of which should be wrong, static{} is executed at the first initialization, and Only executed once; you can tell with the following code:

copy code
package myblog.classloader;

/**
* @project MyBlog
* @create Jun 18, 2013 7:00:45 PM
* @version 1.0.0
* @author Zhang Guang
*/
public class Toy {
        private String name;

        public static final int price=10;
       
        static {
                System.out.println("Initializing");
        }

        Toy() {
                System.out.println("Building");
        }
        Toy(String name) {
                this.setName(name);
        }

        public static String playToy(String player) {
                String msg = buildMsg(player);
                System.out.println(msg);
                return msg;
        }
        private String buildMsg(String player) {
                String msg = player + " plays " + name;
                return msg;
        }
}
  // For the above class, execute the following code:
  Class c = Class.forName("myblog.rtti.Toy");
  // c.newInstance()
;
During initialization, the static{} clause is still executed, but the constructor is not executed, so only Initializing is output, but no Building is output.

Regarding initialization, @AchunAxiao gave a very detailed scenario in the comments of this article, thanks to @AchunAxiao:

According to the java virtual machine specification, all java virtual machine implementations must be used by the java program for the first time in each class or interface. It is initialized only when it is actively used.

There are six types of active use:
1) Create an instance of
a class 2) Access a static variable of a class or interface, or assign a value to the static variable (if you access a static compile-time constant (that is, a constant whose value can be determined at compile time), it will not Causes the initialization of the class)
3) Call the static method of the class
4) Reflection (Class.forName(xxx.xxx.xxx))
5) Initialize a subclass of a class (equivalent to active use of the parent class), but directly through the subclass The class refers to the parent class element and does not cause the initialization of the subclass (see Example 6)
6) The Java virtual machine is marked as the startup class (including the main method) The

class is different from the initialization of the interface. If a class is initialized, then Its parent class or parent interface is also initialized, but if an interface is initialized, it will not cause the initialization of its parent interface.

Example

1, through the above explanation, you can understand the following program (the following program part comes from "Java Programming Ideas"):

Copy code
class Toy {
        static {
                System.out.println("Initializing");// Static clause, only executed once when the class is first loaded and initialized, and only once
        }

        Toy() {
                System.out .println("Building");// Constructor, load every time a new object is declared
        }
}
Copy code
For the above program segment, the first time Class.forName("Toy") is called, the static clause will be executed; If new Toy() is executed afterwards, only the constructor is executed.

2. Pay attention to the newInstance() method

Class cc = Class.forName("Toy");//Get the class (note that you need to use the fully qualified name with the package name)
Toy toy=(Toy)cc.newInstance(); / /Equivalent to a new object, but the Gum class must have a default constructor (no parameters)
3. Both .class and Class.forName can be used to create class applications, but the difference is that Gum.class is used to create a Class When the object is applied, the Class object will not be automatically initialized (the static clause will not be executed)

copy code
public class TestToy {
        public static void main(String[] args) {
                // try {
                // Class c = Class.forName("myblog.classloader.Toy");
                // } catch (ClassNotFoundException e) {
                // e.printStackTrace();
                // }
                Class c = Toy.class; // No value will be output
        }
}
Copy code
Using Toy.class is executed at compile time, so you must already have Toy's .class file at compile time, otherwise it will fail to compile , which is different from Class.forName("myblog.classloader.Toy"), which is dynamically loaded at runtime.

However, if the main method is directly written in the Toy class, then calling Toy.class will cause initialization and output Initializing. The reason is not caused by Toy.class, but because the class contains the startup method main, which will Causes the initialization of the Toy.

4, compile-time constants. Going back to the complete class Toy, if you directly output: System.out.println(Toy.price), you will find that neither the static clause nor the constructor is executed. This is because in Toy, the constant price is limited by static final, like this Constants are called compile-time constants, and for such constants, they can be read without initialization.
A compile-time constant must satisfy three conditions: static, final, and constant.

The following types are not compile-time constants, and their application will cause class initialization: static int a; final int b; static final int c=

ClassInitialization.rand.nextInt (100); static final int d; static {     d=5; } Copy code 5, the essence of the static block. Note the code below: copy code class StaticBlock {         static final int c = 3;         static final int d;         static int e = 5;         static {                 d = 5;                 e = 10;























                System.out.println("Initializing");
        }

        StaticBlock() {
                System.out.println("Building");
        }
}

public class StaticBlockTest {
        public static void main(String[] args) {
                System.out.println( StaticBlock.c);
                System.out.println(StaticBlock.d);
                System.out.println(StaticBlock.e);
        }
}
Copy Code What is the output of
this code? Is Initialing output before c, d, and e, or after? Does e output 5 or 10?

Execute it, the result is:

3
Initializing
5
10
The answer is 3 is output first, Initializing is output later, e output is 10, why?

The reason is this: when outputting c, since c is a compile-time constant, it will not cause class initialization, so it is directly output. When outputting d, d is not a compile-time constant, so it will cause the initialization operation, that is, the execution of the static block, so d is assigned a value of 5, e is assigned a value of 10, then outputs Initializing, then outputs d as 5 and e as 10.

But why e is 10? It turns out that JDK will automatically create a static block for the initialization of e (reference: http://www.java3z.com/cwbwebhome/article/article8/81101.html?id=2497), so the above code is equivalent to:

copy code
class StaticBlock {
        static final int d;

        static int e;
       
        static {
           e=5;
        }

        static {
            d = 5;
            e = 10;
            System.out.println("Initializing");
        }

        StaticBlock() {
            System.out. println("Building");
        }
}   
Copy code
It can be seen that, in order to execute, e is first initialized to 5, and then initialized to 10, so 10 is output.

Similarly, it is easy to think of the following code:

copy code
class StaticBlock {
        static {
                d = 5;
                e = 10;
                System.out.println("Initializing");
        }

        static final int d;

        static int e = 5;

        StaticBlock() {
                System.out.println("Building");
        }
} In
this code, the declaration of e is placed after the static block, so e will be initialized to 10 and then to 5, so
In this code e will output 5.

6. When accessing a static field of a Java class or interface, only the class or interface that actually declares this field will be initialized ("Java Depth Adventure")

copy code
/**
* The example comes from the second "Java Depth Adventure" Chapter
* @author Zhang Guang
*
*/
class B {
        static int value = 100;
        static {
                System.out.println("Class B is initialized");// output
        }
}

class A extends B {
        static {
                System.out.println("Class A is initialized") ; // No output }
        }
public

class SuperClassTest {
        public static void main(String[] args) {
                System.out.println(A.value);// output 100
        }
} The value is referenced, but the value is declared in the parent class B, so only B will be initialized, and the initialization of A will not be caused.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326991221&siteId=291194637