-
加载顺序
有继承关系时:
父类static member>子类 static member>父类成员变量>父类构造方法>子类成员变量>子类构造方法。
单一类时:静态成员变量>非静态成员变量>构造代码块>构造方法
出现多个静态成员变量时,按声明顺序加载。(包含静态代码块) -
深入理解:类静态成员变量仅声明与同时初始化时
仅声明时,遵循 加载顺序
如果静态成员变量声明时同时初始化,则需要先初始化该声明类型的非静态成员及方法。(满足静态变量仅初始化一次)
public class StaticLoadTest {
public static int k = 0;
public static StaticLoadTest t1 ;
public static StaticLoadTest t2 ;
public static int i = print("i");
public static int n = 99;
public int j = print("j");
{
print("非静态构造块");
}
static{
print("静态代码块");
}
public StaticLoadTest (String str) {
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
++n;
++i;
}
public static int print(String str) {
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
++i;
return ++n;
}
public static void main(String[] args) {
StaticLoadTest test= new StaticLoadTest ("init");
}
}
执行结果:
1:i i=0 n=0
2:静态代码块 i=1 n=99
3:j i=2 n=100
4:非静态构造块 i=3 n=101
5:init i=4 n=102
如果声明时初始化t1和t2,将程序改为:
public class StaticTestLoad {
public static int k = 0;
public static StaticTestLoad t1 =new StaticTestLoad("t1") ;
public static StaticTestLoad t2 =new StaticTestLoad("t2");
public static int i = print("i");
public static int n = 99;
public int j = print("j");
{
print("构造块");
}
static{
print("静态块");
}
public StaticTestLoad (String str) {
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
++n;
++i;
}
public static int print(String str) {
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
++i;
return ++n;
}
public static void main(String[] args) {
StaticTestLoad test= new StaticTestLoad ("init");
//StaticTestLoad test2= new StaticTestLoad ("init2");
//StaticTestLoad test3= new StaticTestLoad ("init3");
}
}
运行结果为:
1:j i=0 n=0
2:构造块 i=1 n=1
3:t1 i=2 n=2
4:j i=3 n=3
5:构造块 i=4 n=4
6:t2 i=5 n=5
7:i i=6 n=6
8:静态块 i=7 n=99
9:j i=8 n=100
10:构造块 i=9 n=101
11:init i=10 n=102
程序先初始化了StaticTestLoad 里的非静态成员变量j和构造方法。完成t1和t2初始化后,再按顺序初始化 test。(整个程序,静态变量只被初始化了一遍)
再改程序,将main方法里注释掉的test2和test3打开。
public static void main(String[] args) {
StaticTestLoad test= new StaticTestLoad ("init");
StaticTestLoad test2= new StaticTestLoad ("init2");
StaticTestLoad test3= new StaticTestLoad ("init3");
}
运行结果为:
1:j i=0 n=0
2:构造块 i=1 n=1
3:t1 i=2 n=2
4:j i=3 n=3
5:构造块 i=4 n=4
6:t2 i=5 n=5
7:i i=6 n=6
8:静态块 i=7 n=99
9:j i=8 n=100
10:构造块 i=9 n=101
11:init i=10 n=102
12:j i=11 n=103
13:构造块 i=12 n=104
14:init2 i=13 n=105
15:j i=14 n=106
16:构造块 i=15 n=107
17:init3 i=16 n=108
我把上面输出划分为5个部分,便于理解。
同样遵循加载顺序,并且static类型的只初始化了一遍。
引申阅读:JVM的栈和堆。
statck(栈):存放执行程序,如声明的Book book。通常保存引用对象在heap里的地址信息。
堆(heap):主要用来存放new出对象。
static存储在heap的静态内存区里,全局通用。
- 因此,如果是多线程同时操作同一内存区,程序结果可能不正确。
- 因此,要加线程锁,或者使用局部变量。
网友评论