对象的实例化
对象实例化的几种方式
美团:
- 对象在 JVM 中饭是怎么存储的?
- 对象头信息里面有哪些东西?
蚂蚁金服:
- 二面:Java 对象头里有什么?
对象的实例化:
- 创建对象的方式
new
new
最常见的方式- 变形 1 : Xxx 的静态方法
- 变形 2 : XxxBuilder/XxxFactory 的静态方法
- Class 的
newInstance()
- 反射的方式,只能调用空参的构造器,权限必须是
public
- 反射的方式,只能调用空参的构造器,权限必须是
- Constructor 的
newInstance(Xxx)
- 反射的方式,可以调用空参、带参的构造器。权限没有要求
- 使用
clone()
- 不调用任何构造器,当前类需要实现
Cloneable
接口, 实现clone()
- 不调用任何构造器,当前类需要实现
- 使用反序列化
- 从文件、网络中获取一个对象的二进制流
- 第三方库
Objenesis
- 创建对象的步骤
- 判断对象对应的类是否加载、链接、初始化
虚拟机遇到一条new
指令 ,首先去检查这个指令的参数能否在 Metaspace 的常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解忻和初始化。( 即判断类元信息是否存在)。如果没有,那么在双亲委派模式下,使用当前类加载器以ClassLoader+包名+类名
为 Key 进行查找对应的 .class 文件。如果没有找到文件,则抛出ClassNotFoundException
异常,如果找到,则进行类加载,并生成对应的Class
类对象 - 为对象分配内存
首先计算对象占用空间大小,接着在堆中划分一块内存给新对象。如果实例成员变量是引用变量,仅分配引用变量空间即可,即4个字节大小。- 如果内存规整
- 指针碰撞
- 如果内存不规整
- 虚拟机需要维护一个列表
- 空闲列表分配
- 说明
- 如果内存规整
- 处理并发安全问题
- 采用 CAS 配上失败重试保证更新的原子性
- 每个线程预先分配一块 TLAB
- 初始化分配到的空间
- 所有属性设置默认值,保证对象实例字段在不赋值时可以直接使用
- 设置对象的对象头
- 执行
init
方法进行初始化
- 判断对象对应的类是否加载、链接、初始化
从字节码角度看对象的创建过程