单个类的情况
-
加载类的字节码文件到内存中的方法区
-
初始化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 } } -
通过new在堆内存中申请对象的内存空间,取得首地址。
-
构造方法压栈,依次执行以下的操作
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 } } -
整个对象初始化完成,返回首地址值
当前类有父类的情况
子父类的初始化(分层初始化)
先进行父类静态初始化,然后进行子类静态初始化(加载类文件的先后)。在堆内存空间分配完毕后,然后父类对象初始化,在进行子类对象初始化。(堆内存的创建,在父类对象的基础上加东西变成子类对象)
每一个的初始化流程就是单个类的初始化流程。
/*
父类的静态代码块执行
子类的静态代码块执行
父类的构造函数执行
子类的构造函数执行
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
}
}