The Java Language Specification explains the process of initializing a class.
A class or interface type T will be initialized immediately before the
first occurrence of any one of the following:
T is a class and an instance of T is created.
T is a class and a static method declared by T is invoked.
A static field declared by T is assigned.
A static field declared by T is used and the field is not a constant variable (§4.12.4).
T is a top level class (§7.6), and an assert statement (§14.10) lexically nested within T (§8.1.3) is executed.
and with more details
[...]
Synchronize on the initialization lock, LC, for C. This involves
waiting until the current thread can acquire LC.
[...]
If the Class object for C indicates that initialization is in progress
for C by the current thread, then this must be a recursive request for
initialization. Release LC and complete normally.
[...]
Next, if C is a class rather than an interface, and its superclass SC
has not yet been initialized, then recursively perform this entire
procedure for SC. If necessary, verify and prepare SC first. If the
initialization of SC completes abruptly because of a thrown exception,
then acquire LC, label the Class object for C as erroneous, notify all
waiting threads, release LC, and complete abruptly, throwing the same
exception that resulted from initializing SC.
So
new B();
requires that class B
be initialized. Because B
is a sub class of A
, A
needs to be initialized. While initializing A
, this
static {
System.out.println("loading A static 2 B.c= "+B.c);
}
indicates that B
needs to be initialized, but B
is already in the process of being initialized, so it is ignored for now and A
initialization continues. Because B
's initialization is not complete, the field c
has not yet been initialized to 50, so it prints 0
.
A
initializing completes. B
initializing continues. B
initializing completes and Boom! you're done.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…