首先看下类的生命周期 :
对象的创建其实包含了初始化和实例化两个阶段,我们在使用一个对象时,JVM首先会检查相关类型是否已经加载并初始化,如果没有,则JVM立即进行加载并调用类构造器完成类的初始化。在类初始化过程中或初始化完毕后,根据具体情况才会去对类进行实例化。
实例化时候,java虚拟机就会为其分配内存来存放自己及其从父类继承过来的实例变量。在为这些实例变量分配内存的同时,这些实例变量先会被赋予默认值(零值)。在内存分配完成之后,Java虚拟机才会对新创建的对象赋予我们程序员给定的值
创建一个对象包含下面两个过程:
1、类构造器完成类初始化(分配内存、赋予默认值)
2、类实例化(赋予给定值)
/**
* @program: ard
* @description:
* @author: dongcunxiao
* @create: 2020-05-26 15:42
**/
public class Person {
// 静态变量
public static String staticField = "静态变量";
// 普通变量
private String name = "普通变量";
// 静态代码块
static {
System.out.println(staticField);
System.out.println("静态代码快");
}
// 初始化块
{
System.out.println(name);
System.out.println("初始化块");
}
// 构造方法
public Person() {
System.out.println("构造器");
}
public static void main(String[] args) {
new Person();
}
}
静态变量
静态代码快
普通变量
初始化块
构造器
然后定义一个子类
package com.gw.ard.gateway.controller.order;
/**
* @program: ard
* @description:
* @author: dongcunxiao
* @create: 2020-05-26 15:48
**/
public class ZhangSan extends Person {
// 静态变量
public static String staticField = "ZhangSan -- 静态变量";
// 普通变量
private String name = "ZhangSan --普通变量";
// 静态代码块
static {
System.out.println(staticField);
System.out.println("ZhangSan --静态代码快");
}
// 初始化块
{
System.out.println(name);
System.out.println("ZhangSan --初始化块");
}
// 构造方法
public ZhangSan() {
System.out.println("ZhangSan --构造器");
}
public static void main(String[] args) {
new Person();
}
}
结果:
Person -- 静态变量
Person --静态代码快
ZhangSan -- 静态变量
ZhangSan --静态代码快
Person --普通变量
Person --初始化块
Person --构造器
类的初始化顺序,这样看确实不好记,不过没有继承关系的我们都能很好的看到。带继承关系的
总结:
构建对象 根据Person类元信息确定对象的大小,向JVM堆中申请一块内存区域并构建对象的默认信息(加载Person对象成员变量信息并赋默认值如 int类型为0,引用类型为null)。
初始化对象: 然后执行对象内部生成的init方法,初始化成员变量值,同时执行搜集到的{}代码块逻辑,最后执行对象构造方法。 引用对象: 对象实例化完毕后,再把栈中的Person对象引用地址指向Person对象在堆内存中的地址。
对象头:
对象头里主要包括几类信息,分别是锁状态标志、持有锁的线程ID、,GC分代年龄、对象HashCode,类元信息地址、数组长度,这里并没有对对象头里的每个信息都列出而是进行大致的分类,下面是对其中几类信息进行说明。
锁状态标志: 对象的加锁状态分为无锁、偏向锁、轻量级锁、重量级锁几种标记。
持有锁的线程: 持有当前对象锁定的线程ID。
GC分代年龄: 对象每经过一次GC还存活下来了,GC年龄就加1。
类元信息地址: 可通过对象找到类元信息,用于定位对象类型。
数组长度: 当对象是数组类型的时候会记录数组的长度