最详细类初始化的顺序,一看就懂

这方面知识一直没有整理,但大家经常讨论类的静态变量、成员变量、静态初始化块、非静态初始化块、构造器,及继承父类时,它们的初始化顺序都是怎样的,所以找了个机会认真整理一下,帮助大家脱坑:
首先介绍一下这几个家伙,捋清它们是干嘛的:
静态变量 / 成员变量: 是类的属性,静态变量属于类,被static修饰,成员变量属于对象实例。
静态成员方法 / 普通成员方法: 静态成员方法属于类所有,类实例化前即可使用,普通成员方法可以访问类中的任何成员,静态成员方法只能访问类中的静态成员。
静态初始化块 / 非静态初始化块: 初始化块是类的成员之一,每次类的创建会隐式的调用它。本质上是一个代码块,或方法体。静态的被static修饰。
构造器: 用于实例化对象,分为有参无参。
这些都是类的基本结构。下面通过代码示例分析它们的执行顺序:

示例1

public class DateTest {

		
		public static void main(String[] args) {
			System.out.println((int)(Math.random()*40+1));
			System.out.println(Demo1.a);//加载类
			//new Demo1();执行两次,第一次不执行实例化,第二次执行实例化
		}
	}
	class Demo1{
		static int a =100;
		{
			System.out.println("我是普通初始化块");
		}
		static{
			System.out.println("我是静态初始化块");
		}
	}

第一次输出:
最详细类初始化的顺序,一看就懂_第1张图片
第二次输出:
最详细类初始化的顺序,一看就懂_第2张图片
两次比较后我们就可以知道:
普通初始化块:创建对象时隐式调用
静态初始化块:类加载时隐式调用

示例2

public class DateTest {
	public static void main(String[] args) {
		new Demo2();
		new Demo2();
		new Demo2();
		new Demo2();
		new Demo2();
	}
}
class Demo2{
	static int a =100;
	{
		System.out.println("我是普通初始化块");
	}
	static{
		System.out.println("我是静态初始化块");
	}
}

最详细类初始化的顺序,一看就懂_第3张图片
由这个例子我们又知道:
静态初始化块只在类加载时调用一次,而普通初始化块随着创建对象而执行。

示例3

public class DateTest {
	public static void main(String[] args) {
		Demo3 qiyu = new Demo3();
	}
}
class Demo3{
	public Demo3(){
		System.out.println("我是构造器");
	}
	String a=msg("普通属性1");
	public static String msg(String info){
		System.out.println(info);
		return info;
	}
	static{
		System.out.println("静态初始化块2");
	}
	static String b=msg("静态属性1");
	{
		System.out.println("我是普通初始化块1");
	}
	String c=msg("普通属性2");
	{
		System.out.println("我是普通初始化块2");
	}
	static String d=msg("静态属性2");
	static{
		System.out.println("静态初始化块1");
	}
}

最详细类初始化的顺序,一看就懂_第4张图片
由本例可知:在一个类中如果有多个不同的初始化块,初始化属性,构造器,
执行顺序是:静态初始化块|静态变量 > 普通初始化块|普通变量 > 构造器

示例四

public class DateTest {
	public static void main(String[] args) {
		Demo3 qiyu = new Demo3();
	}
}
class Demo3{
	public Demo3(){
		System.out.println("我是构造器");
	}
	
	String a=msg("普通属性1");
	public static String msg(String info){
		System.out.println(info);
		return info;
	}
	static{
		System.out.println("静态初始化块2");
		new Demo3();
	}
	static String b=msg("静态属性1");
	{
		System.out.println("我是普通初始化块1");
	}
	String c=msg("普通属性2");
	{
		System.out.println("我是普通初始化块2");
	}
	static String d=msg("静态属性2");
	static{
		System.out.println("静态初始化块1");
	}
}

最详细类初始化的顺序,一看就懂_第5张图片
本例比较有特色,产生了嵌套,即在某个静态初始化块中new了新对象,我们发现,一开始先执行静态初始化块,没问题,但后面并没有执行下一层的静态初始化块,而执行的普通属性和普通初始化块,这是由于如果一直优先执行静态初始化块的话会产生死循环,此时虚拟机将执行静态块的权利只赋予最先进行实例化的类,这样就能防止死循环的产生。

你可能感兴趣的:(最详细类初始化的顺序,一看就懂)