对象创建的方式

对象的创建

说到对象的创建,首先让我们看看 Java 中提供的几种对象创建方式:

Header 解释
使用new关键字 调用了构造函数
使用Class的newInstance方法 调用了构造函数
使用Constructor类的newInstance方法 调用了构造函数
使用clone方法 没有调用构造函数
使用反序列化 没有调用构造函数

无论何时我们调用一个对象的 clone方法, JVM都会创建一个新的对象,将前面对象的内容全部拷贝进去。用 clone方法创建对象并不会调用任何构造函数。

为了使用 clone方法,我们需要先实现 Cloneable接口并实现其定义的 clone方法。

本文以 new关键字为例,讲述 JVM堆中对象实例的创建过程如下:

  1. 当虚拟机遇到一条 new指令时,首先会检查这个指令的参数能否在常量池中定位一个符号引用。然后检查这个符号引用的类字节码对象是否加载、解析和初始化。如果没有,将执行对应的类加载过程。
  2. 类加载 完成以后,虚拟机将会为新生对象分配内存区域,对象所需内存空间大小在类加载完成后就已确定。
  3. 内存分配 完成以后,虚拟机将分配到的内存空间都初始化为零值
  4. 虚拟机对对象进行一系列的设置,如所属类的元信息对象的哈希码对象GC分带年龄线程持有的锁偏向线程ID 等信息。这些信息存储在对象头( ObjectHeader)。

上述工作完成以后,从虚拟机的角度来说,一个新的对象已经产生了。然而,从 Java程序的角度来说,对象创建才刚开始。

对象的布局

HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头Header)、实例数据InstanceData)和对齐填充Padding)。

对象的访问定位

Java程序需要通过 JVM 栈上的引用访问堆中的具体对象。对象的访问方式取决于 JVM 虚拟机的实现。目前主流的访问方式有 句柄直接指针 两种方式。

指针: 指向对象,代表一个对象在内存中的起始地址。句柄: 可以理解为指向指针的指针,维护着对象的指针。句柄不直接指向对象,而是指向对象的指针(句柄不发生变化,指向固定内存地址),再由对象的指针指向对象的真实内存地址。