从字符串到常量池,一文看懂String类设计 (2)

如果要看懂这两行代码,我们需要对常量池中String类型常量的结构有一定了解,其结构如下:

CONSTANT_String_info tag 标志常量类型的标签
  index   指向字符串字面量的索引  

对应到我们上面的字节码中,tag=String,index=#14,所以我们可以知道,#2是一个字面量为#14的字符串类型常量。而#14对应的字面量信息(一个Utf8类型的常量)就是dmz。

常量池作为资源仓库,最大的用处在于被class文件中的其它结构所引用,这个时候我们再将注意力放到main方法上来,对应的就是这三条指令

0: ldc #2 // String dmz 2: astore_1 3: return

ldc:这个指令的作用是将对应的常量的引用压入操作数栈,在执行ldc指令时会触发对它的符号引用进行解析,在上面例子中对应的符号引用就是#2,也就是常量池中的第二个元素(这里就能看出方法表中就引用了常量池中的资源)

astore_1:将操作数栈底元素弹出,存储到局部变量表中的1号元素

return:方法返回值为void,标志方法执行完成,将方法对应栈帧从栈中弹出

下面我用画图的方式来画出整个流程,主要分为四步

解析ldc指令的符号引用(#2)

将#2对应的常量的引用压入到操作数栈顶

将操作数栈的元素弹出并存储到局部变量表中

执行return指令,方法执行结束,弹出栈区该方法对应的栈帧

第一步:

从字符串到常量池,一文看懂String类设计

在解析#2这个符号引用时,会先到字符串常量池中查找是否存在对应字符串实例的引用,如果有的话,那么直接返回这个字符串实例的引用,如果没有的话,会创建一个字符串实例,那么将其添加到字符串常量池中(实际上是将其引用放入到一个哈希表中),之后再返回这个字符串实例对象的引用。

到这里也能回答我们之前提出的那个问题了,一个对象是new出来的,另外一个是在解析常量池的时候JVM自动创建的

第二步:

image-20200616215838415

将第一步得到的引用压入到操作数栈,此时这个字符串实例同时被操作数栈以及字符串常量池引用。

第三步:

image-20200616220344102

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zypdgs.html