JVM笔记 - 06类从上到下的初始化顺序


说明:笔记内容来源于《北京圣思园教育 - 张龙老师 - 深入理解JVM》视频课程。如有侵权,请联系删除。

1 类加载、连接、初始化的回顾

JVM笔记 - 01类加载器深入解析与阶段分解
JVM笔记 - 02类的加载、连接、始化过程详解
前面两篇内容,介绍了类的加载、连接、初始化,及主动使用类的场景。

2 类从上到下的初始化顺序

2.1 案例1

静态变量counter2的声明赋值,在构造方法前面

package com.test;

public class MyTest6 {

	public static void main(String[] args) {
		Singleton singleton = Singleton.getInstance();
		System.out.println("main=====counter1:" + singleton.counter1);
		System.out.println("main=====counter2:" + singleton.counter2);
	}
}

class Singleton {
	public static int counter1;
	//在构造函数的前面
	public static int counter2 = 0;
	
	private static Singleton singleton = new Singleton();
	private Singleton() {
		counter1++;
		counter2++;
		System.out.println("Singleton=====counter1:" + counter1);
		System.out.println("Singleton=====counter2:" + counter2);
	}
	
	public static Singleton getInstance() {
		return singleton;
	}
}

执行结果为:
在这里插入图片描述
执行结果分析:
① main()方法中,"Singleton.getInstance()"调用了Singleton的静态方法,是对Singleton的主动使用

public class MyTest6 {

	public static void main(String[] args) {
		Singleton singleton = Singleton.getInstance();
		System.out.println("main=====counter1:" + singleton.counter1);
		System.out.println("main=====counter2:" + singleton.counter2);
	}
}

② 对Singleton的主动使用,会初始化Singleton。
在初始化Singleton之前,会先加载、连接Singleton
③ 连接Singleton,具体分为3个步骤:验证 -> 准备 -> 解析
④ 在连接的准备阶段,为会Singleton的静态变量分配内存,并将静态变量初始化为默认值。
准备阶段完成后,Singleton的静态变量的状态如下

//int的默认值为0
counter1 = 0;
counter2 = 0;
//引用类型的默认值为null
singleton = null;

⑤ 在初始化阶段,会为Singleton的静态变量赋予正确的初始值。
初始化的顺序,就是代码编写的顺序。

class Singleton {
	public static int counter1;
	//在构造函数的前面
	public static int counter2 = 0;
	
	private static Singleton singleton = new Singleton();
	private Singleton() {
		counter1++;
		counter2++;
		System.out.println("Singleton=====counter1:" + counter1);
		System.out.println("Singleton=====counter2:" + counter2);
	}
}

第1步,初始化counter1,因为代码中没有为counter1设置具体的数值,所以counter1的值仍然是准备阶段的默认值,即0
第2步,初始化counter2,因为代码中给counter2赋值为0,所以counter2的值是代码中设定的值,即0
第3步,初始化singleton,初始化singleton会执行构造函数。
在构造函数中,对counter1、counter2分别进行了自增1的操作,所以构造函数执行完成后,counter1值有0变为了1、counter2的值由0变为了1
⑥ 所以,main()方法中,打印counter1、counter2的值,得到的结果分别为 counter1 = 1,counter2 = 1

2.2 案例2

静态变量counter2的声明赋值,在构造方法后面

package com.test;

public class MyTest6 {

	public static void main(String[] args) {
		Singleton singleton = Singleton.getInstance();
		System.out.println("main=====counter1:" + singleton.counter1);
		System.out.println("main=====counter2:" + singleton.counter2);
	}
}

class Singleton {
	public static int counter1;
	
	private static Singleton singleton = new Singleton();
	private Singleton() {
		counter1++;
		counter2++;
		System.out.println("Singleton=====counter1:" + counter1);
		System.out.println("Singleton=====counter2:" + counter2);
	}
	
	//在构造函数的后面
	public static int counter2 = 0;
	
	public static Singleton getInstance() {
		return singleton;
	}	
}

执行结果为:
在这里插入图片描述
执行结果分析:
①、②、③、④,案例1和案例2是相同的
⑤ 在初始化阶段,会为Singleton的静态变量赋予正确的初始值。
初始化的顺序,就是代码编写的顺序。

class Singleton {
	public static int counter1;
	private static Singleton singleton = new Singleton();
	private Singleton() {
		counter1++;
		counter2++;
		System.out.println("Singleton=====counter1:" + counter1);
		System.out.println("Singleton=====counter2:" + counter2);
	}
	
	//在构造函数的后面
	public static int counter2 = 0;
	public static Singleton getInstance() {
		return singleton;
	}
}

第1步,初始化counter1,因为代码中没有为counter1设置具体的数值,所以counter1的值仍然是准备阶段的默认值,即0
第2步,初始化singleton,初始化singleton会执行构造函数。
在构造函数中,对counter1、counter2分别进行了自增1的操作,所以构造函数执行完成后,counter1值由0变为了1、counter2的值由0变为了1
第3步,初始化counter2,因为代码中给counter2赋值为0,所以counter2的值是代码中设定的值,即0。
因为counter2的位置在构造函数的后面,
所以在执行构造函数后,counter2 = 1,在counter2初始化完成后,counter2 = 0
⑥ 所以,main()方法中,打印counter1、counter2的值,得到的结果分别为 counter1 = 1,counter2 = 0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值