Coding & Life

求知若饥,虚心若愚

0%

java加载顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class Main { // 1.第一步,准备加载类

public static void main(String[] args) {
new Main(); // 4.第四步,执行main方法,new一个类,但在new之前要处理匿名代码块
}

static int num = 4; // 2.第二步,静态变量和静态代码块的加载顺序由编写先后决定

{
num += 3;
System.out.println("b"); // 5.第五步,按照顺序加载匿名代码块,代码块中有打印
}

int a = 5; // 6.第六步,按照顺序加载变量

{ // 成员变量第三个
System.out.println("c"); // 7.第七步,按照顺序打印c
}

Main() { // 类的构造函数,第四个加载
System.out.println("d"); // 8.第八步,最后加载构造函数,完成对象的建立
}

static { // 3.第三步,静态块,然后执行静态代码块,因为有输出,故打印a
System.out.println("a");
}

static void run() // 静态方法,调用的时候才加载 注意看,e没有加载
{
System.out.println("e");
}
}

执行以上代码可以总结加载顺序:静态代码块(静态变量) -> 匿名代码块(成员变量) -> 构造方法 -> 静态方法(不调用不加载

  • 静态代码块只加载一次
  • 静态方法只有调用才会加载
  • 静态代码块和静态变量按照代码编写前后顺序执行
  • 匿名代码块和成员变量按照代码编写前后顺序执行
1
2
3
4
5
public class Print {
public Print(String s) {
System.out.println(s + " ");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Parent {
public static Print obj1 = new Print("1");

public Print obj2 = new Print("2");

public static Print obj3 = new Print("3");

static {
new Print("4");
}

public static Print obj4 = new Print("5");

public Print obj5 = new Print("6");

public Parent() {
new Print("7");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Child extends Parent {
static {
new Print("a");
}

public static Print obj1 = new Print("b");

public Print obj2 = new Print("c");

public Child() {
new Print("d");
}

public static Print obj3 = new Print("e");

public Print obj4 = new Print("f");

public static void main(String[] args) {
Parent obj1 = new Child();

Parent obj2 = new Child();
}
}

执行main方法打印顺序:1 3 4 5 a b e 2 6 7 c f d 2 6 7 c f d

  • 先执行父类的静态代码块和静态变量初始化,并且静态代码块和静态变量的执行顺序只跟代码中出现的顺序有关;
  • 执行子类的静态代码块和静态变量初始化;
  • 执行父类的实例变量初始化;
  • 执行父类的构造函数;
  • 执行子类的实例变量初始化;
  • 执行子类的构造函数;

如果类已经被加载,则静态代码块和静态变量就不用重复执行,再创建类对象时,只执行与实例相关变量初始化和构造方法