According to On Java 8: Chapter 6 initialization and cleanup - constructor initialization summary
1, The order in which data (variables, methods, code blocks) in an object are initialized (summary)
Order: static variable (static code block) > non static variable (non static code block) > static method > non static method
No matter how many objects are created, static data only occupies a storage area and is initialized once.
1. Variables in class:
- Variables in a class are initialized before any methods in the class (including constructors) are called. [that is, variables are initialized before all methods]
- The order in which variables are defined determines the order in which they are initialized
- Initialization of static variables takes precedence over non static variables (regardless of definition order)
2. Methods in class:
- Initialization of static methods takes precedence over non static methods
- Constructors are actually static methods
3. Object:
- Initialization of static objects takes precedence over non static objects (provided that static objects are not initialized before, because static data will be initialized only once.)
For static data:
- No matter how many objects are created, static data occupies only one storage area.
- When the bytecode (. Class) file corresponding to a class is loaded, all actions related to static initialization will be executed. Therefore, static initialization is initialized only once when the class object is first loaded.
Static and non static code blocks:
- Static code blocks, like other static initialization actions, are executed only once
- A non static code block (without static) is executed every time an object is created. It is executed every time it is created. (you can use it to ensure that some operations will happen)
- The instance initialization clause is executed before the constructor. (static code blocks are the same, and static code blocks are equivalent to static variables. The initialization order between them is the same as that between variables.)
- It can be considered that in terms of initialization order: you can treat static code blocks as static variables and non static code blocks as ordinary variables.
2, Constructor initialization
Constructor can be used for initialization, which gives you more flexibility because you can call methods for initialization at run time. However, this does not prevent automatic initialization, which occurs before the constructor is called. Therefore, if the following code is used:
// housekeeping/Counter.java public class Counter { int i; Counter() { i = 7; } //... }
i is initialized to 0 first and then to 7. This is true for all basic types and references, including variables whose initial values have been explicitly specified at the time of definition. Therefore, the compiler does not force you to initialize elements somewhere in the constructor or before using them -- initialization is already guaranteed.
Order of initialization
(initialization order of variables:) the order in which variables are defined in a class determines their initialization order. Even if variable definitions are interspersed between method definitions, they are initialized before any method (including constructor) is called. For example:
// housekeeping/OrderOfInitialization.java // Demonstrates initialization order // When the constructor is called to create a // Window object, you'll see a message: class Window { Window(int marker) { System.out.println("Window(" + marker + ")"); } } class House { Window w1 = new Window(1); // Before constructor House() { // Show that we're in the constructor: System.out.println("House()"); w3 = new Window(33); // Reinitialize w3 } Window w2 = new Window(2); // After constructor void f() { System.out.println("f()"); } Window w3 = new Window(3); // At end } public class OrderOfInitialization { public static void main(String[] args) { House h = new House(); h.f(); // Shows that construction is done } } //Output: Window(1) Window(2) Window(3) House() Window(33) f()
In the House class, the definitions of several Window objects are deliberately scattered to prove that they will all be initialized before calling the constructor or other methods. In addition, w3 is assigned again in the constructor.
As can be seen from the output, the reference w3 is initialized twice: once before calling the constructor and once during the constructor call (the first referenced object will be discarded and garbage collected). This may seem inefficient at first glance, but ensures correct initialization. Imagine if an overloaded constructor is defined, in which w3 is not initialized, and w3 is defined without an initial value, what will happen? (just a reference)
Initialization of static data
No matter how many objects are created, static data occupies only one storage area. The static keyword cannot be applied to local variables, so it can only act on attributes (fields, domains). If a field is a static primitive type and you do not initialize it, it will get the standard initial value of the primitive type. If it is an object reference, its default initial value is null.
If you initialize at definition time, static variables look like non static variables.
The following example shows when a static store is initialized:
// housekeeping/StaticInitialization.java // Specifying initial values in a class definition class Bowl { Bowl(int marker) { System.out.println("Bowl(" + marker + ")"); } void f1(int marker) { System.out.println("f1(" + marker + ")"); } } class Table { static Bowl bowl1 = new Bowl(1); Table() { System.out.println("Table()"); bowl2.f1(1); } void f2(int marker) { System.out.println("f2(" + marker + ")"); } static Bowl bowl2 = new Bowl(2); } class Cupboard { Bowl bowl3 = new Bowl(3); static Bowl bowl4 = new Bowl(4); Cupboard() { System.out.println("Cupboard()"); bowl4.f1(2); } void f3(int marker) { System.out.println("f3(" + marker + ")"); } static Bowl bowl5 = new Bowl(5); } public class StaticInitialization { public static void main(String[] args) { System.out.println("main creating new Cupboard()"); new Cupboard(); System.out.println("main creating new Cupboard()"); new Cupboard(); table.f2(1); cupboard.f3(1); } static Table table = new Table(); static Cupboard cupboard = new Cupboard(); } //Output: Bowl(1) Bowl(2) Table() f1(1) Bowl(4) Bowl(5) Bowl(3) Cupboard() f1(2) main creating new Cupboard() Bowl(3) Cupboard() f1(2) main creating new Cupboard() Bowl(3) Cupboard() f1(2) f2(1) f3(1)
The Bowl class shows the creation of a class, while Table and Cupboard contain static data members of the Bowl type in their class definitions. Note that before the static data member is defined, a non static member of Bowl type is defined in the Cupboard class b3. (the result is still the static data members of Bowl type displayed first: bowl4 and bowl5).
As can be seen from the output, static initialization is only carried out when necessary. If you do not create a Table object or reference Table.bowl1 or Table.bowl2, the static Bowl class objects bowl1 and bowl2 will never be created. They are initialized only when the first Table object is created (or accessed). After that, the static object is not initialized again.
The order of initialization is first static objects (if they have not been initialized before), then non static objects, as can be seen from the output. To execute the main() method, the StaticInitialization class must be loaded. Its static properties table and cupboard are then initialized, which will cause their corresponding classes to be loaded. Since they both contain static Bowl objects, the Bowl class will also be loaded. Therefore, in this special program, all classes will be loaded before the main() method. This is usually not the case, because in a typical program, everything is not connected through static as shown in this example.
To summarize the process of creating objects, suppose there is a class named Dog:
-
Even if the static keyword is not explicitly used, the constructor is actually a static method. Therefore, when creating a Dog type object for the first time or accessing a static method or property of a Dog class for the first time, the Java interpreter must look in the class path to locate Dog.class.
-
When the Dog.class is loaded (as you will learn later, a Class object will be created), all actions related to static initialization will be executed. Therefore, static initialization is initialized only once when the Class object is first loaded.
-
When you create an object with new Dog(), you will first allocate enough storage space for the Dog object on the heap.
-
The allocated storage space will be cleared first, that is, all basic type data in the Dog object will be set to the default value (the number will be set to 0, and the Boolean and character types are the same), and the reference will be set to null.
-
Perform all initialization actions that appear at the field definition.
-
Execute constructor. As you will see in the chapter "reuse", this may involve many actions, especially when it comes to inheritance.
Explicit static initialization (static code block)
You can put a set of static initialization actions in a special "static clause" (sometimes called a static block) in the class. Like this:
// housekeeping/Spoon.java public class Spoon { static int i; static { i = 47; } }
This looks like a method, but in fact it's just a block of code following the static keyword. Like other static initialization actions, this code is executed only once: when the object of the class is created for the first time or when the static member of the class is accessed for the first time (it is not even necessary to create the object of the class). For example:
// housekeeping/ExplicitStatic.java // Explicit static initialization with "static" clause class Cup { Cup(int marker) { System.out.println("Cup(" + marker + ")"); } void f(int marker) { System.out.println("f(" + marker + ")"); } } class Cups { static Cup cup1; static Cup cup2; static { cup1 = new Cup(1); cup2 = new Cup(2); } Cups() { System.out.println("Cups()"); } } public class ExplicitStatic { public static void main(String[] args) { System.out.println("Inside main()"); Cups.cup1.f(99); // [1] } // static Cups cups1 = new Cups(); // [2] // static Cups cups2 = new Cups(); // [2] } //Output: Inside main Cup(1) Cup(2) f(99)
Whether you access the static cup1 object through the line marked [1], or remove the line marked [1] and let it run the line marked [2] (remove the comment of [2]), the static initialization action of Cups will be executed. If both [1] and [2] are annotated, the static initialization of Cups will not be performed. In addition, whether to remove all or only one of the comments marked [2], static initialization will only be performed once.
Non static instance initialization (non static code block)
Java provides a similar syntax called instance initialization to initialize non static variables of each object, such as:
// housekeeping/Mugs.java // Instance initialization class Mug { Mug(int marker) { System.out.println("Mug(" + marker + ")"); } } public class Mugs { Mug mug1; Mug mug2; { // [1] mug1 = new Mug(1); mug2 = new Mug(2); System.out.println("mug1 & mug2 initialized"); } Mugs() { System.out.println("Mugs()"); } Mugs(int i) { System.out.println("Mugs(int)"); } public static void main(String[] args) { System.out.println("Inside main()"); new Mugs(); System.out.println("new Mugs() completed"); new Mugs(1); System.out.println("new Mugs(1) completed"); } } //Output: Inside main Mug(1) Mug(2) mug1 & mug2 initialized Mugs() new Mugs() completed Mug(1) Mug(2) mug1 & mug2 initialized Mugs(int) new Mugs(1) completed
It looks like a static code block, except for the static keyword. This syntax is necessary to support the initialization of "anonymous inner classes" (see Chapter "inner classes"), but you can also use it to ensure that some operations will occur, no matter which constructor is called. From the output, the instance initialization clause is executed before the two constructors.