对象实例化发生了什么反应

336 阅读3分钟
先看问题

1.可以从字节码的角度说说对象的创建过程?

2.可以从执行步骤角度说说对象的创建过程吗?


查看字节码文件

创建一个Test.java文件

image.png


通过javap -verbose -p 命令查看生成的字节码文件

image.png


说明一下:

javap的指令:

1.new 创建一个新对象

2.dup 复制栈顶部一个字长内容

3.调用需要特殊处理的实例方法:invokespecial

从字节码角度分析

1NEW


如果找不到Class对象,则进行类加载。加载成功后,则在堆中分配内存,从Object开始到本类路径上的所有属性都要分配内存。分配完毕后,进行零值初始化。在分配过程中,注意引用是占据储存空间的,它是一个变量,占用4个字节。这个指令完毕后,将指向实例对象的引用变量压入虚拟机栈顶。


2DMP


在栈顶复制该引用变量,这时的栈顶有两个指向堆内实例对象的引用变量。如果<init>方法有参数,还需要把参数压入操作栈中。两个引用变量的目的不同,其中压至底下的引用用于赋值,或者保存到局部变量表中,另一个栈顶的引用变量作为句柄调用相关方法。


3INVOKESPECIAL


调用对象实例方法,通过栈顶的引用变量调用<init>方法。<clinit>是类初始化执行的方法,而<init>是对象初始化执行的方法。

从执行步骤的角度分析


1.确认类元信息是否存在。当JVM接收到new指令时,首先在metaspace内检查需要创建的类元信息是否存在。若不存在,那么在双亲委派模式下,使用当前类加载器以ClassLoader+包名+类名为Key进行查找对应的.class文件。如果没有找到文件,则抛出ClassNotFoundException异常;如果找到,则进行类加载,并生成对应的Class类对象。


2.分配对象内存。首先计算对象占用空间大小,如果实例成员变量是引用变量,仅分配引用变量空间即可,即4个字节大小,接着在堆中划分一块内存给新对象。在分配内存空间时,需要进行同步操作,比如采用CAS(Compare And Swap)失败重试、区域加锁等方法保证分配操作的原子性。


3.设定默认值。成员变量值都需要设定为默认值,即各种不同形式的零值。


4.设置对象头。设置新对象的哈希码、GC信息、锁信息、对象所属类元素信息等。这个过程取决于JVM的实现


5.执行init方法。初始化成员变量,执行实例化代码块,调用类的构造方法,并把堆内对象的首地址赋值给引用变量。


关注51码农网,寻找一起进步的码农。www.51manong.com

51码农网,程序员社群学习打卡集聚地

关注微信公众号:51码农网

51码农公众平台.jpg