对象实例化过程:
1.首先分析一下内存空间
- 堆空间(Heap) : 使用new来开辟的堆内存空间,储存对象
- 栈空间(Stack) :用来储存一些变量的,基础数据类型、对象的引用(对象堆空间地址)
栈存取速度比堆要快,仅次于直接位于CPU中的寄存器
- 方法区(Methd) :线程共享区域,储存类信息,常量,静态变量,即时编译器编译后的代码等数据
2.对象实例化:
(1)首先,静态代码块在加载时就执行了,所以肯定是最先执行的;
(2)对于非静态代码块会在构造方法中的代码块之前加载
运行结果:
static成员在加载字节码文件到内存过程是会被优先执行,静态成员变量会在方法区优先初始化
(3)具体过程:
(4)若存在继承关系:
继承的过程:在jvm装载类的准备阶段,首先为类的所有类属性和类初始化块分配内存空间,并在类首次初始化阶段中为其进行初始化,类属性和类初始化块之间的定义时的顺序决定了其初始化的顺序;若类存在父类,则首先初始化父类的类属性和类初始化块,一直上溯到Object类最先执行。
所以加载顺序为:
父类静态代码块->子类静态代码块->父类非静态代码块->父类构造函数->
子类非静态代码块->子类构造函数
遵循规则
- 静态代码块->普通代码块->构造方法
- 先父类后子类
- 先静态后非静态
3.补充:
jvm 加载类进内存时,会先加载父类,然后加载子类
在初始化类时,先对类属性进行默认初始化,然后调用其构造函数进行显示初始化
而在构造函数中,会先调用父类构造函数进行初始化:
(1)先对父类属性进行默认初始化,然后初始化父类构造函数;
(2)父类初始化完后,再初始化子类属性,然后子类构造函数进行初始化;
(3)初始化完后把地址赋值给子类的引用变量;
public class Person{ private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; System.out.println("这是Person构造函数"); this.show(); } public void show() { System.out.println("这是Person show()函数"); } }
public class Student extends Person { public Student(String name, int age){ super(name,age); System.out.println("这是Student构造函数"); super.show(); show(); } public void show() { System.out.println("这是Student show()函数"); } public static void main(String[] args){ Student student = new Student("uzi",23); } }
运行结果:
这是Person构造函数
这是Student show()函数
这是Student构造函数
这是Person show()函数
这是Student show()函数