Java虚拟机-创建对象的过程

本文深入探讨了Java中创建对象的几种方式,包括new、反射、clone和反序列化等。详细阐述了从字节码角度理解new操作的六个步骤,涉及类加载、内存分配、并发安全处理、对象初始化等关键环节。同时,分析了不同内存分配策略在内存规整和不规整情况下的处理。最后,总结了对象头的设置以及init方法的执行在对象初始化过程中的作用。
摘要由CSDN通过智能技术生成

文章目录

对象的实例化

  • 创建对象的方式

    1. new
    2. Class的newInstance :反射的方式,只能调用空参的构造器,必须是public
    3. Constructor的newInstance(xxx):反射的方式,可以调用有参数或者无参数构造器,权限没有要求。
    4. 使用clone。不调用任何构造器,当前类需要实现Cloneable接口,实现 clone()方法。
    5. 使用反序列化:从文件或者网络获取流
    6. 第三方库Objenesis
  • 创建对象的步骤

    1. 判断对象对应的类是否加载、链接、初始化
    2. 为对象分配内存
    3. 处理并发安全问题
    4. 初始化分配到空间
    5. 设置对象的对象头
    6. 执行init方法进行初始化
  • 下面看看简单new一个对象,从字节码角度看看创建对象的过程。

  public static void main(java.lang.String[]);
  // 参数 返回值Void
    descriptor: ([Ljava/lang/String;)V
    // 一些标志位 
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
    // 操作数栈深度2 本地变量表2哥 参数是1个
      stack=2, locals=2, args_size=1
      // new 指令 #2 对应查找常量池中的 java/lang/Object 方法,会先判断类是否已经加载,如果没加载会先进行类加载。然后开辟堆空间 然后初始化一些默认值
         0: new           #2                  // class java/lang/Object
         3: dup // 复制栈空间的操作数栈
         4: invokespecial #1                  // Method java/lang/Object."<init>":()V  // 调用<init> 执行构造器 读取参数加入操作数栈 进行赋值等操作
         7: astore_1 // 加入局部变量表 
         8: return // 返回
      LineNumberTable:
        line 7: 0
        line 8: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  args   [Ljava/lang/String;
            8       1     1 object   Ljava/lang/Object;
}

  • 从执行步骤来看创建对象的过程

1: 判断对象对应的类是否加载、链接、初始化
当虚拟机接收到new指令的时候,首先去检测Metaspace的常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经类加载解析和初始化(类元信息是否已经存在)。如果没有那么在双亲委派的模式下,使用当前类加载器进行查找对应的.class 文件。如果没有找到则抛出 ClassNotFoundException 异常。如果找到则进行类加载,并生成对应的Class类对象。

2:为对象分配内存
->如果内存规整:比如Serial、ParNew;垃圾回收算法采用的是标记压缩算法,所以内存规整连续,所以采用指针碰撞的方式,指针向后移动为对象分配空间。
->如果内存不规整:已使用的内存和未使用的内存相互交错,那么虚拟机采用的是空闲列表法为对象分配内存。(就是维护了一个列表,需要分配内存的时候去查列表哪里够就分配到哪里)(CMS采用的标记清除算法)

3: 处理并发安全问题:
a:采用CAS失败重试、区域加锁保证原子性。
b:为每个线程预先分配TLAB

4:初始化分配到空间:
所有属性设置默认值:保证对象实例字段在不赋值的情况下可以使用。

5:设置对象的对象头
将对象的所属类,对象的HashCode、对象的GC信息、锁信息、等数据存储在对象头。

6:执行init进行初始化
在Java程序的角度看来,此时初始化才正式开始,初始化成员变量、执行实例化代码、调用类的构造方法、并把堆对象的地址赋值给引用变量(一般来说看字节码是否有 invokespecial指令所决定)、这样一个真正的对象就创建出来了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值