Java对象初始化的完整流程

3,576 阅读4分钟

单个类的情况

  1. 加载类的字节码文件到内存中的方法区

  2. 初始化static相关的静态成员变量和静态成员方法,称为类初始化。(全部在方法区)

    2.1 先把所有的static部分(成员与方法)申请空间,然后再给每一个static成员由上至下分配初始值 。

    2.2 分配完空间后,所有的静态成员变量都会有一个默认值

    2.3 然后执行(显示赋值,静态代码块)对变量进行赋值,执行顺序与代码顺序一致

    public class Test2 {
    	static {
    		b = 6; //b先被分配空间,默认赋值0,然后才执行到这里
    	}
    	
    	public static int a = 1;
    	public static int b = 2; //静态代码块执行后,又对b的值进行修改
    	public static int c;
    	
    	public static void main(String[] args) {
    		System.out.println(Test2.b); //2
    	}
    }
    
  3. 通过new在堆内存中申请对象的内存空间,取得首地址。

  4. 构造方法压栈,依次执行以下的操作

    4.1 把类的非静态成员变量加载到堆内存中并分配空间同时默认初始化,非静态成员方法加载到方法区中并分配空间。然后由上到下进行非静态成员变量的初始化。

    4.2 用构造代码块和显示赋值对成员变量进行赋值,执行顺序与代码顺序一致 4.3 执行构造函数。

    public class Test3 {
    	{
    		a = 10; //a先被分配空间,默认赋值0,然后才执行到这里
    	}
    	public int a = 2; //静态代码块执行后,又对a的值进行修改
    	
    	public Test3() {
    		System.out.println("构造方法执行"); //构造代码块与显示赋值结束后,才走构造
    	}
    	
    	public static void main(String[] args) {
    		Test3 t = new Test3();
    		System.out.println(t.a); //2
    	}
    }
    
  5. 整个对象初始化完成,返回首地址值

当前类有父类的情况

子父类的初始化(分层初始化)

先进行父类静态初始化,然后进行子类静态初始化(加载类文件的先后)。在堆内存空间分配完毕后,然后父类对象初始化,在进行子类对象初始化。(堆内存的创建,在父类对象的基础上加东西变成子类对象)

每一个的初始化流程就是单个类的初始化流程。

/*
父类的静态代码块执行
子类的静态代码块执行
父类的构造函数执行
子类的构造函数执行
777
999
*/

class Father {
	public static int fa = 10;
	public int faNum = 777;
	static {
		System.out.println("父类的静态代码块执行"); 
	}
	
	public Father() {
		System.out.println("父类的构造函数执行"); 
	}

}

class Son extends Father {
	public static int son = 10;
	public int sonNum = 999;
	
	static {
		System.out.println("子类的静态代码块执行"); 
	}
	
	public Son() {
		System.out.println("子类的构造函数执行"); 
	}
}

public class ExtendsTest {
	public static void main(String[] args) {
		Son s = new Son();
		System.out.println(s.faNum); 
		System.out.println(s.sonNum); 
	}
}

小结

在创建对象时,先进行类加载,然后static变量的初始化,然后是成员变量的初始化。变量都一定是先分配空间,再初始化,再使用的。

参考博客

https://www.cnblogs.com/atom-wangzh/p/8718323.html

面试题单个类

/*
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

如果main方法不执行任何语句,也会输出到8位置
*/

public class Test {

	public static int k = 0;
	public static Test t1 = new Test("t1");
	public static Test t2 = new Test("t2");
	public static int i = print("i");
	public static int n = 99;
	public int j = print("j");
	
	static {
		print("静态块");
	}
		
	public Test(String str) {
		System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
		i++;
		n++;
	}
	
	{
		print("构造块");
		
	}
	
	public static int print(String str) {
		System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
		n++;
		return ++i;
	}

	
	public static void main(String[] args) {
		Test t = new Test("init");
		//System.out.println("j = " + t.j); //9
	}

}

面试题带父类

/*

父类的静态代码块执行了
父类的构造方法执行了 f=10 //说明在子类对象初始化前,父类对象初始化已经完成
1:j i=0 n=0
2:构造块 i=1 n=1
3:t1 i=2 n=2
父类的构造方法执行了 f=10
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

*/

class Father {
	public int f = 10;
	
	static {
		System.out.println("父类的静态代码块执行了");
	}
	
	public Father() {
		System.out.println("父类的构造方法执行了 f="+f );
	}
}


public class Test extends Father{

	public static int k = 0;
	public static Test t1 = new Test("t1");
	public static Test t2 = new Test("t2");
	public static int i = print("i");
	public static int n = 99;
	public int j = print("j");
	
	static {
		print("静态块");
	}
		
	public Test(String str) {
		System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
		i++;
		n++;
	}
	
	{
		print("构造块");
		
	}
	
	public static int print(String str) {
		System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
		n++;
		return ++i;
	}

	
	public static void main(String[] args) {
		
		//Test t = new Test("init");
		//System.out.println("j = " + t.j); //9
	}

}