对象实例化
创建对象的方式
-
new:最常见的方式、Xxx的静态方法,XxxBuilder/XxxFactory的静态方法
-
Class的newInstance方法:反射的方式,只能调用空参的构造器,权限必须是public
-
Constructor的newInstance(XXX):反射的方式,可以调用空参、带参的构造器,权限没有要求
-
使用clone():不调用任何的构造器,要求当前的类需要实现Cloneable接口,实现clone()
-
使用序列化:从文件中、从网络中获取一个对象的二进制流
-
第三方库 Objenesis
对象实例化过程
- 加载类元信息(判断对象对应的类是否加载、链接、初始化)
- 为对象分配内存
- 处理并发问题
- 属性的默认初始化(零值初始化)
- 设置对象头信息
- 属性的显示初始化、代码块中初始化、构造器中初始化
对象内存布局
对象头
对象头包含了两部分,分别是运行时元数据(Mark Word)和类型指针。如果是数组,还需要记录数组的长度
运行时元数据
-
哈希值(HashCode)
-
GC分代年龄
-
锁状态标志
-
线程持有的锁
-
偏向线程ID
-
翩向时间戳
类型指针
指向类元数据InstanceKlass,确定该对象所属的类型。
实例数据
它是对象真正存储的有效信息,包括程序代码中定义的各种类型的字段(包括从父类继承下来的和本身拥有的字段)
-
相同宽度的字段总是被分配在一起
-
父类中定义的变量会出现在子类之前
-
如果CompactFields参数为true(默认为true):子类的窄变量可能插入到父类变量的空隙
对象填充
不是必须的,也没有特别的含义,仅仅起到占位符的作用。
对象的访问方式
句柄访问
reference中存储稳定句柄地址,对象被移动(垃圾收集时移动对象很普遍)时只会改变句柄中实例数据指针即可,reference本身不需要被修改
直接指针(HotSpot虚拟机采用)
直接指针是局部变量表中的引用,直接指向堆中的实例,在对象实例中有类型指针,指向的是方法区中的对象类型数据