一、类的二进制字节码包含哪些信息

要理解常量池是什么,先看看类的二进制字节码包含哪些信息!!!

  • 常量池
  • 类的基本信息(比如:类的访问权限、类的名称、实现了哪些接口)
  • 类的方法定义(包含了虚拟机指令,也就是把我们代码编译为了虚拟机指令 )

二、通过反编译字节码验证

1、测试代码

将下面的测试代码使用javac 编译为 *.class文件

public class HelloWorld {public static void main(String[] args) {System.out.println("hello world");}
}

2、javap反编译*.class字节码

先将示例代码编译为 *.class 文件,然后将class文件反编译为JVM指令码。然后观察 *.class字节码中到底包含了哪些部分。

// ===========================================类的描述信息===============================================
Classfile /xx/xx/xx/xx/HelloWorld.classLast modified 2021-10-12; size 569 bytesMD5 checksum 7f4f0fe4b6e6d04ddaf30401a7b04f07Compiled from "HelloWorld.java"
public class org.memory.jvm.t5.HelloWorldminor version: 0major version: 49flags: ACC_PUBLIC, ACC_SUPER// ===========================================常量池===============================================
Constant pool:#1 = Methodref          #6.#20         // java/lang/Object."<init>":()V#2 = Fieldref           #21.#22        // java/lang/System.out:Ljava/io/PrintStream;#3 = String             #23            // hello world#4 = Methodref          #24.#25        // java/io/PrintStream.println:(Ljava/lang/String;)V#5 = Class              #26            // org/memory/jvm/t5/HelloWorld#6 = Class              #27            // java/lang/Object#7 = Utf8               <init>#8 = Utf8               ()V#9 = Utf8               Code#10 = Utf8               LineNumberTable#11 = Utf8               LocalVariableTable#12 = Utf8               this#13 = Utf8               Lorg/memory/jvm/t5/HelloWorld;#14 = Utf8               main#15 = Utf8               ([Ljava/lang/String;)V#16 = Utf8               args#17 = Utf8               [Ljava/lang/String;#18 = Utf8               SourceFile#19 = Utf8               HelloWorld.java#20 = NameAndType        #7:#8          // "<init>":()V#21 = Class              #28            // java/lang/System#22 = NameAndType        #29:#30        // out:Ljava/io/PrintStream;#23 = Utf8               hello world#24 = Class              #31            // java/io/PrintStream#25 = NameAndType        #32:#33        // println:(Ljava/lang/String;)V#26 = Utf8               org/memory/jvm/t5/HelloWorld#27 = Utf8               java/lang/Object#28 = Utf8               java/lang/System#29 = Utf8               out#30 = Utf8               Ljava/io/PrintStream;#31 = Utf8               java/io/PrintStream#32 = Utf8               println#33 = Utf8               (Ljava/lang/String;)V// =======================================虚拟机中执行编译的方法===========================================
{public org.memory.jvm.t5.HelloWorld();descriptor: ()Vflags: ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 7: 0LocalVariableTable:Start  Length  Slot  Name   Signature0       5     0  this   Lorg/memory/jvm/t5/HelloWorld;// main方法JVM指令码public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)V// main方法访问修饰符描述flags: ACC_PUBLIC, ACC_STATIC// main方法中的代码执行部分// ===============================解释器读取下面的JVM指令解释并执行===================================             Code:stack=2, locals=1, args_size=1// 从常量池中符号地址为 #2 的地方,先获取静态变量System.out0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;// 从常量池中符号地址为 #3 的地方加载常量 hello world3: ldc           #3                  // String hello world// 从常量池中符号地址为 #3 的地方获取要执行的方法描述,并执行方法输出hello world5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V// main方法返回8: return// ==================================解释器读取上面的JVM指令解释并执行================================// 行号映射表LineNumberTable:line 9: 0line 10: 8// 局部变量表LocalVariableTable:Start  Length  Slot  Name   Signature0       9     0  args   [Ljava/lang/String;
}

三、什么是常量池以及常量池的作用

1、什么是常量池

从上面的反编译字节码中可以看到,Class的常量池其实就是一张记录着该类的一些常量、方法描述、类描述、变量描述信息的表。

2、常量池中有什么内容

常量池中主要存放两类数据,一是字面量、二是符号引用

字面量:

  • 比如String类型的字符串值或者定义为final类型的常量的值。

符号引用:

  • 类或接口的全限定名(包括他的父类和所实现的接口)
  • 变量或方法的名称
  • 变量或方法的描述信息
  • this

可参考:https://blog.csdn.net/Hellowenpan/article/details/101389330

3、常量池的作用

在解释器解释执行每条JVM指令码的时候,根据这些指令码的符号地址去常量池中找到对应的描述。然后解释器就知道该执行哪个类的那个方法、方法的参数是什么等。

拿上面反编译的字节码指令来说明:

  1. 当解释器解释执行main方法的时候,读取到下面的11行JVM指令码0: getstatic #2
  2. getstatic指令表示获取一个静态变量,#2表示该静态变量的符号地址,解释器通过#2符号地址去常量池中查找#2对应的静态变量
  3. 然后解释器继续向下运行,执行第13行的3: ldc #3指令,该指令的含义是:从常量池中加载符号地址为 #3 的常量
  4. 然后解释器继续向下运行,执行第15行的5: invokevirtual #4指令,该指令的含义是:执行方法,那么要执行哪个方法呢?执行常量池中符号地址为 #4 的方法。
  // main方法JVM指令码public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)V// main方法访问修饰符描述flags: ACC_PUBLIC, ACC_STATIC// main方法中的代码执行部分// ===============================解释器读取下面的JVM指令解释并执行===================================             Code:stack=2, locals=1, args_size=1// 从常量池中符号地址为 #2 的地方,先获取静态变量System.out0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;// 从常量池中符号地址为 #3 的地方加载常量 hello world3: ldc           #3                  // String hello world// 从常量池中符号地址为 #3 的地方获取要执行的方法描述,并执行方法输出hello world5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V// main方法返回8: return// ==================================解释器读取上面的JVM指令解释并执行================================

四、运行时常量池

1、什么是运行时常量池

上面我们分析了常量池其实就是一张对照表,常量池是 *.class 文件中的。当类的字节码被加载到内存中后,他的常量池信息就会集中放入到一块内存,这块内存就称为运行时常量池,并且把里面的符号地址为真实地址

2、符号地址变为真实地址怎么理解

①、符号地址

从上面的反编译后的JVM字节码指令可以看到有这么一条指令0: getstatic #2,解释器解释执行JVM指令的时候,通过指令中的 #x去常量池中获取需要的值。这里的#2其实就是符号地址,标识这某个变量在常量池中的某个位置。

②、真实地址

在程序运行期,当*.Class文件被加载到内存以后,常量池中的这些描述信息就会被放到内存中,其中的 #x会被转化为内存中的地址(真实地址)。

③、简单总结

符号地址变为真实地址其实就是,在*.class文件被加载到内存以后,将*.class文件中常量池中的#x符号地址,转化为内存中的地址。

JVM常量池和运行时常量池相关推荐

  1. [转载] java常量池-字符串常量池、class常量池和运行时常量池

    参考链接: 如何在Java中初始化和比较字符串 原文链接:http://tangxman.github.io/2015/07/27/the-difference-of-java-string-pool ...

  2. 字符串常量池、class常量池和运行时常量池

    原文链接:http://tangxman.github.io/2015/07/27/the-difference-of-java-string-pool/ 在java的内存分配中,经常听到很多关于常量 ...

  3. class 常量池、字符串常量池和运行时常量池的区别

    文章目录 class 常量池.字符串常量池和运行时常量池的区别 概念 常量池(Constant Pool) 字符串常量池(String Pool) 运行时常量池( Runtime Constant P ...

  4. Java虚拟机的静态常量池和运行时常量池

    (静态)常量池:用于存放编译器生成的各种字面量和符号引用(符号引用区别于直接引用,后者在class字节码文件被虚拟机解析之后,符号引用将被替换为直接引用). 运行时常量池:(静态)常量池中的内容在类加 ...

  5. Java中的常量池(字符串常量池、class常量池和运行时常量池)

    简介: 这几天在看Java虚拟机方面的知识时,看到了有几种不同常量池的说法,然后我就去CSDN.博客园等上找资料,里面说的内容真是百花齐放,各自争艳,因此,我好好整理了一下,将我自认为对的理解写下来与 ...

  6. 3.内存分配、逃逸分析与栈上分配、直接内存和运行时常量池、基本类型的包装类和常量池、TLAB、可达性分析算法(学习笔记)

    3.JVM内存分配 3.1.内存分配概述 3.2.内存分配–Eden区域 3.3.内存分配–大对象直接进老年代 3.3.1.背景 3.3.2.解析 3.4.内存分配–长期存活的对象进去老年代 3.5. ...

  7. jvm的类加载和运行时数据区和垃圾回收

    类加载过程 加载(loading) 引导类加载器 扩展类加载器 系统类加载器 1.通过一个类的全限定名获取此类的二进制字节流 2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构 3.在内 ...

  8. jvm运行时类加载机制_JVM体系结构:JVM类加载器和运行时数据区

    jvm运行时类加载机制 各位读者好! 在JVM系列的上一篇文章中,开发人员了解了Java虚拟机(JVM)及其体系结构. 本教程将帮助开发人员正确回答以下主题的问题: ClassLoader子系统 运行 ...

  9. JVM体系结构:JVM类加载器和运行时数据区

    各位读者好! 在JVM系列的上一篇文章中,开发人员了解了Java虚拟机(JVM)及其体系结构. 本教程将帮助开发人员正确回答以下主题的问题: ClassLoader子系统 运行时数据区 1.简介 在继 ...

最新文章

  1. Acwing145. 超市[C++题解]:贪心
  2. Oracle Enterprise Manager Cloud Control最新文档合集
  3. vue 如何将参数放到连接上_通过Vue路由传参的两种方式及Vue组件中接收参数的方式...
  4. 电脑c语言怎么调出来的,c语言系统源代码_C语言判断系统版本的代码怎样将值调出来啊...
  5. Java的native方法-----你必须要知道的JAVA知识
  6. ionic3 生命周期
  7. HDU - 4422 The Little Girl who Picks Mushrooms
  8. OTL翻译(4) -- otl_stream类
  9. python 腾讯视频签到_腾讯视频自动签到脚本.
  10. UG装配体,打开后总显示卸载的一种可行解决办法
  11. linux中oracle中文乱码问题
  12. win7添加java环境变量path_Win7怎么配置Java环境变量?
  13. Ps(Adobephoto shop)当中布尔运算的使用方法
  14. 百度地图点击触发事件介绍
  15. css3动画2D|3D
  16. AI轻松入门,AI零基础入门,AI初级教学,
  17. 三星带着Bixby搅局中国市场,还说自己是「一家AI技术公司」
  18. 手写数字识别--Android Studio 加载tensorflow模型
  19. 如何编写稳定流畅的iOS移动端应用
  20. mysql select符合查询_mysql学习-select查询,子查询,联接查询,union,intersect,except联合...

热门文章

  1. 骨骼肌神经-肌接头的化学影响因素
  2. fpga图像处理(基于sd卡图像读取和显示)
  3. 5-20日U-file开放注册,以及一大波福利活动正在临近,包含基础版和V+账户升级,免费领取流量包
  4. linux find查找文件并删除文件,Linux find 查找 并删除文件 杀掉进程
  5. WinSetupFromUSB 制作XP USB启动盘
  6. UWP OneNote for Win 10 同步修复的又一案例 其实不是Proxy和APPContainer沙盒的错 AppContainer Loopback还不够
  7. 开科唯识冲刺创业板:年营收3.7亿 红杉奕信是二股东
  8. 有没有测试女生暗恋的软件,判断一个女生有多喜欢你?有一套专门的“测试方法”,一试便知...
  9. ffmpeg合并两个视频
  10. ue怎么打开服务器隐藏文件,隐藏/显示选区命令 - UltraEdit 中文帮助文档