1.背景
最近又要开始做java项目,周末重温了一遍java基础。创建一个对象,虽然只有B b = new B()这么一步就可以达到目的,但你清楚这个步骤背后jvm是如何操作的吗,对于一般变量、静态变量、静态代码块、构造方法等,是怎样的加载顺序?本文将和你一起探讨~
2. 案例说明
- 父类A.class
public class A {
int v1 = 1;
static int v2 = 2;
static {
System.out.println("A的静态块");
}
public A() {
System.out.println("A的构造方法");
}
}
- 子类B.class
public class B extends A {
int v3 = 1;
static int v4 = 2;
static {
System.out.println("B的静态块");
}
public B() {
System.out.println("B的构造方法");
}
}
- 测试类 Test.class
public class Test {
public static void main(String[] args) {
System.out.println("第一次创建B对象");
B b1 = new B();
System.out.println("第二次创建B对象");
B b2 =new B();
}
}
3. 测试结果
断点运行测试类的main方法,可以看到每一步的加载顺序如下:
图3.1 第1次创建B对象的加载顺序
图3.2 第2次创建B对象的加载顺序
最终的测试结果如下:
可以看到,加载类只会执行一次,第二次创建B对象时,就不会再加载A类和B类的静态变量和静态代码块了。 以上只是程序中可以测试的创建步骤,但是不要忘记还有虚拟机中为我们完成的内存分配等步骤吖。
4. 总结
B b1 = new B() 的详细执行过程:(虚拟机中完成1、2、5、6步,其他步骤可以进行演示)
- 第一次使用A类和B类:(加载类只执行一次!!!)
1. 在方法区加载父类A,并且会为父类A的静态变量分配内存(V2初始化成0,未赋值);
2. 在方法区加载子类B,并且会为子类B的静态变量分配内存(V3初始化成0,未赋值);
3. 执行父类A的静态变量赋值运算,和父类A的静态初始化块;(执行顺序遵循代码写的顺序)
4. 执行子类B的静态变量赋值运算,和子类B的静态初始化块;(执行顺序遵循代码写的顺序)
- 开始创建对象:
5. 创建父类对象A,为父类的非静态变量分配内存;
6. 创建子类对象B,为子类的非静态变量分配内存;
7. 执行父类非静态变量的赋值运算;
8. 执行父类的构造方法;
9. 执行子类非静态变量的赋值运算;
10.执行子类的构造方法。
以上就是对象创建十步法,若有纰漏,欢迎指正,一起学习!