问题
public class DataFactory {
private static DataFactory ourInstance = new DataFactory();
static {
System.out.println("static initialize");
}
private DataFactory() {
System.out.println("constructor");
}
public static void doNothing() {
System.out.println("inside doNothing");
}
}
public class App {
public static void main(String[] args) {
System.out.println("main start");
DataFactory.doNothing();
}
And After I run it, here is the printed sequence:
main start
constructor
static initialize
inside doNothing
Why calling DataFactory.doNothing() will trigger Constructor? and why constructor is running before the static initializer?
回答1:
When the class is initialized, it'll execute all of the static {...}
and static field initializers, in the order they appear in the code (see JLS 12.4.2, and in particular step 9 in the list of steps there). In your example, there are two such initializers:
private static DataFactory ourInstance = new DataFactory();
- The
static {...}
block
So, the first one happens first. It instantiate an object and assigns its reference to ourInstance
. To instantiate the object, it needs to call the constructor, which it does (as you saw).
When that's done, the static block is executed, which prints "static initialize."
At this point, the class is initialized, and the method doNothing
can finally be invoked.
回答2:
It's invoking the constructor because you are creating an instance of DataFactory
inside the same DataFactory
; so it needs to call the constructor once in order to be able to instantiate it. Comment or delete the private static DataFactory ourInstance = new DataFactory();
line and the constructor call is not going to happens.
A static
initializer is executed right after the class is initialized.
回答3:
Sorry to tell that Rod_Algonquin is incomplete and Machina too. The right answer is that:
"Static Initialization Blocks run when the class is first loaded"
So, you are correct to ask "why the constructor is run before static?!".
How can? And there is a rule for initialization blocks (statics and instance).
The order in which initialization blocks appear in a class matters.
Just swap the order of your static initialization block to the static instantiation to see what happen:
public class DataFactory {
static { //// SWAPPED HERE
System.out.println("static initialize");
}
///// SWAPPED HERE
private static DataFactory ourInstance = new DataFactory();
private DataFactory() {
System.out.println("constructor");
}
public static void doNothing() {
System.out.println("inside doNothing");
}
}
OUTPUT:
main start
static initialize
constructor
inside doNothing
回答4:
Your static field initialization calls the constructor.
In the end, the code that initializes the field "ourInstance" is also part of the static initializer.
So what is actually happening is:
public class DataFactory {
private static DataFactory ourInstance;
static {
outInstance = new DataFactory(); // 2
System.out.println("static initialize"); // 4
}
private DataFactory() {
System.out.println("constructor"); // 3
}
public static void doNothing() {
System.out.println("inside doNothing"); // 6
}
}
public class App {
public static void main(String[] args) {
System.out.println("main start"); // 0
DataFactory.doNothing(); // 1 (static init) and 5 (method call)
}
}
回答5:
Here is the JLS documentation for the constructor:
Constructors are invoked by class instance creation expressions (§15.9)
And the JLS documentation for the static block:
A static initializer declared in a class is executed when the class is initialized (§12.4.2).
As you can see the constructor is first called when the class is initialized and then right after the constructor call then the static block is then called.
来源:https://stackoverflow.com/questions/29359923/why-this-weird-order-of-constructor-static-initializer-static-member-function-in