JVM常量池的深入讲解

论坛 期权论坛 脚本     
niminba   2021-5-23 04:25   1745   0

提示:这里咱们要说的常量池,常量池就是咱们面试中所说的常量池,谈谈你对常量池的认识?面试官一问咱们就懵逼了,你要记得你脑子中有一张图!!! 剩下的就好办了

提示:请各位大佬批评指正!!

前言

提示:学习的时候会有点头疼哦

一、Class常量池与运行时常量池

Class常量池可以理解为是Class文件中的资源仓库。 Class文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项信息就是 常量池(constant pool table) ,用于存放编译期生成的各种 字面量(Literal)和符号引用(Symbolic References)

还是回到前面说的class文件的16进制大体结构如下图:

在这里插入图片描述

对应的含义如下,细节可以查下oracle官方文档

在这里插入图片描述

当然我们一般不会去人工解析这种16进制的字节码文件,我们一般可以通过javap命令生成更可读的JVM字节码指令文件:

javap -v Test.class

public class com.qjc.construction.Test
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #7.#27         // java/lang/Object."<init>":()V
   #2 = Class              #28            // com/qjc/construction/Test
   #3 = Methodref          #2.#27         // com/qjc/construction/Test."<init>":()V
   #4 = Methodref          #2.#29         // com/qjc/construction/Test.test:()I
   #5 = Fieldref           #30.#31        // java/lang/System.out:Ljava/io/PrintStream;
   #6 = Methodref          #32.#33        // java/io/PrintStream.println:(Ljava/lang/Object;)V
   #7 = Class              #34            // java/lang/Object
   #8 = Utf8               <init>
   #9 = Utf8               ()V
  #10 = Utf8               Code
  #11 = Utf8               LineNumberTable
  #12 = Utf8               LocalVariableTable
  #13 = Utf8               this
  #14 = Utf8               Lcom/qjc/construction/Test;
  #15 = Utf8               test
  #16 = Utf8               ()I
  #17 = Utf8               a
  #18 = Utf8               I
  #19 = Utf8               b
  #20 = Utf8               c
  #21 = Utf8               main
  #22 = Utf8               ([Ljava/lang/String;)V
  #23 = Utf8               args
  #24 = Utf8               [Ljava/lang/String;
  #25 = Utf8               SourceFile
  #26 = Utf8               Test.java
  #27 = NameAndType        #8:#9          // "<init>":()V
  #28 = Utf8               com/qjc/construction/Test
  #29 = NameAndType        #15:#16        // test:()I
  #30 = Class              #35            // java/lang/System
  #31 = NameAndType        #36:#37        // out:Ljava/io/PrintStream;
  #32 = Class              #38            // java/io/PrintStream
  #33 = NameAndType        #39:#40        // println:(Ljava/lang/Object;)V
  #34 = Utf8               java/lang/Object
  #35 = Utf8               java/lang/System
  #36 = Utf8               out
  #37 = Utf8               Ljava/io/PrintStream;
  #38 = Utf8               java/io/PrintStream
  #39 = Utf8               println
  #40 = Utf8               (Ljava/lang/Object;)V

Constant pool: 就是class常量池信息,常量池中主要存放两大类常量:字面量和符号引用。

字面量

字面量就是指由字母、数字等构成的字符串或者数值常量

字面量只可以右值出现,所谓右值是指等号右边的值,如:int a=1 这里的a为左值,1为右值。在这个例子中1就是字面量。

int a = 1;
int b = 2;
int c = "abcdefg";
int d = "abcdefg";

符号引用

符号引用是编译原理中的概念,是相对于直接引用来说的。主要包括了以下三类常量:

  • 类和接口的全限定名
  • 字段的名称和描述符
  • 方法的名称和描述符

上面的a,b就是字段名称,就是一种符号引用,还有Test类常量池里的 Lcom/qjc/construction/Test; 是类的全限定名,main和上面的a,b就是字段名称,就是一种符号引用,还有Test类常量池里的 Lcom/qjc/construction/Test; 是类的全限定名,main和test是方法名称,()是一种UTF8格式的描述符,这些都是符号引用。

这些常量池现在是静态信息,只有到运行时被加载到内存后,这些符号才有对应的内存地址信息,这些常量池一旦被装入内存就变成运行时常量池,对应的符号引用在程序加载或运行时会被转变为被加载到内存区域的代码的直接引用,也就是我们说的动态链接了。例如,test()这个符号引用在运行时就会被转变为test(,:/9&alyn.:ah9aykz+'9c..cy%c"9al#9&.#i&i&+/c.

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1060120
帖子:212021
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP