简介

JVM在运行的时候会对class文件进行加载,链接和初始化的过程。class文件中定义的常量池在JVM加载之后会发生什么神奇的变化呢?快来看一看吧。

class文件中的常量池

之前我们在讲class文件的结构时,提到了每个class文件都有一个常量池,常量池中存了些什么东西呢?

字符串常量,类和接口名字,字段名,和其他一些在class中引用的常量。

运行时常量池

但是只有class文件中的常量池肯定是不够的,因为我们需要在JVM中运行起来。

这时候就需要一个运行时常量池,为JVM的运行服务。

运行时常量池和class文件的常量池是一一对应的,它就是class文件的常量池来构建的。

运行时常量池中有两种类型,分别是symbolic references符号引用和static constants静态常量。

其中静态常量不需要后续解析,而符号引用需要进一步进行解析处理。

什么是静态常量,什么是符号引用呢? 我们举个直观的例子。

String site="www.flydean.com"

上面的字符串”www.flydean.com”可以看做是一个静态常量,因为它是不会变化的,是什么样的就展示什么样的。

而上面的字符串的名字“site”就是符号引用,需要在运行期间进行解析,为什么呢?

因为site的值是可以变化的,我们不能在第一时间确定其真正的值,需要在动态运行中进行解析。

静态常量详解

运行时常量池中的静态常量是从class文件中的constant_pool构建的。可以分为两部分:String常量和数字常量。

String常量

String常量是对String对象的引用,是从class中的CONSTANT_String_info结构体构建的:

CONSTANT_String_info {

u1 tag;

u2 string_index;

}

tag就是结构体的标记,string_index是string在class常量池的index。

string_index对应的class常量池的内容是一个CONSTANT_Utf8_info结构体。

CONSTANT_Utf8_info {

u1 tag;

u2 length;

u1 bytes[length];

}

CONSTANT_Utf8_info是啥呢?它就是要创建的String对象的变种UTF-8编码。

我们知道unicode的范围是从0x0000 至 0x10FFFF。

变种UTF-8就是将unicode进行编码的方式。那是怎么编码呢?

从上图可以看到,不同的unicode范围使用的是不同的编码方式。

注意,如果一个字符占用多个字节,那么在class文件中使用的是 big-endian 大端优先的排列方式。

如果字符范围在FFFF之后,那么使用的是2个3字节的格式的组合。

讲完class文件中CONSTANT_String_info的结构之后,我们再来看看从CONSTANT_String_info创建运行时String常量的规则:

规则一:如果String.intern之前被调用过,并且返回的结果和CONSTANT_String_info中保存的编码是一致的话,表示他们指向的是同一个String的实例。

规则二:如果不同的话,那么会创建一个新的String实例,并将运行时String常量指向该String的实例。最后会在这个String实例上调用String的intern方法。调用intern方法主要是将这个String实例加入字符串常量池。

数字常量

数字常量是从class文件中的CONSTANT_Integer_info, CONSTANT_Float_info, CONSTANT_Long_info和 CONSTANT_Double_info 构建的。

符号引用详解

符号引用也是从class中的constant_pool中构建的。

对class和interface的符号引用来自于CONSTANT_Class_info。

对class和interface中字段的引用来自于CONSTANT_Fieldref_info。

class中方法的引用来自于CONSTANT_Methodref_info。

interface中方法的引用来自于CONSTANT_InterfaceMethodref_info。

对方法句柄的引用来自于CONSTANT_MethodHandle_info。

对方法类型的引用来自于CONSTANT_MethodType_info。

对动态计算常量的符号引用来自于CONSTANT_MethodType_info。

对动态计算的call site的引用来自于CONSTANT_InvokeDynamic_info。

String Pool字符串常量池

我们在讲到运行时常量池的时候,有提到String常量是对String对象的引用。那么这些创建的String对象是放在什么地方呢?

没错,就是String Pool字符串常量池。

这个String Pool在每个JVM中都只会维护一份。是所有的类共享的。

String Pool是在1.6之前是存放在方法区的。在1.8之后被放到了java heap中。

注意,String Pool中存放的是字符串的实例,也就是用双引号引起来的字符串。

那么问题来了?

String name = new String("www.flydean.com");

到底创建了多少个对象呢?

总结

class文件中常量池保存的是字符串常量,类和接口名字,字段名,和其他一些在class中引用的常量。每个class都有一份。

运行时常量池保存的是从class文件常量池构建的静态常量引用和符号引用。每个class都有一份。

字符串常量池保存的是“字符”的实例,供运行时常量池引用。

运行时常量池是和class或者interface一一对应的,那么如果一个class生成了两个实例对象,这两个实例对象是共享一个运行时常量池还是分别生成两个不同的常量池呢?欢迎小伙伴们留言讨论。

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

python中常量池和堆_JVM详解之:运行时常量池相关推荐

  1. JVM详解之:运行时常量池

    文章目录 简介 class文件中的常量池 运行时常量池 静态常量详解 String常量 数字常量 符号引用详解 String Pool字符串常量池 总结 简介 JVM在运行的时候会对class文件进行 ...

  2. python argv 详解_对python中的argv和argc使用详解

    主要问题 为什么argv中第一个,即index=0的内容就是文件名? python中argc是用什么实现的? 概念解释 argc:argument counter,命令行参数个数 argv:argum ...

  3. Python中的__name__和__main__含义详解

    背景 在写Python代码和看Python代码时,我们常常可以看到这样的代码: ? 1 2 3 4 5 def main():     ...... if __name__ == "__ma ...

  4. python的raw_ input是什么意思-对python中raw_input()和input()的用法详解

    最近用到raw_input()和input()来实现即时输入,就顺便找了些资料来看,加上自己所用到的一些内容,整理如下: 1.raw_input() raw_input([prompt]) -> ...

  5. python中str和input_对python中raw_input()和input()的用法详解

    最近用到raw_input()和input()来实现即时输入,就顺便找了些资料来看,加上自己所用到的一些内容,整理如下: 1.raw_input() raw_input([prompt]) -> ...

  6. python3 isinstance用法_对python中assert、isinstance的用法详解

    1. assert 函数说明: Assert statements are a convenient way to insert debugging assertions into a program ...

  7. python中关于深拷贝和浅拷贝的详解

    python中关于深拷贝和浅拷贝的详解 概述 在python的语法中,有两种变量的拷贝方式 一种是深拷贝,一种是浅拷贝 我们先说深拷贝 语法 这里需要通过导入系统的copy模块中的deepcopy才可 ...

  8. python中zip的使用_浅谈Python中的zip()与*zip()函数详解

    前言 1.实验环境: Python 3.6: 2.示例代码地址:下载示例: 3.本文中元素是指列表.元组.字典等集合类数据类型中的下一级项目(可能是单个元素或嵌套列表). zip(*iterables ...

  9. python中验证码连通域分割的方法详解

    python中验证码连通域分割的方法详解 这篇文章主要给大家介绍了关于python中验证码连通域分割的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用python具有一定的参考学习价值,需 ...

最新文章

  1. Linux文本比较命令:diff
  2. Linux centosVMware Tomcat介绍、安装jdk、安装Tomcat
  3. 机器学习实验中的编程技术(part4)--模型持久化
  4. [css] 使用rem布局时怎样合理设置根标签字体大小?
  5. android数据库给单选赋值,如何使用android studio将单选按钮的值保存到mysql数据库?...
  6. linux ip 访问记录,linux 精确记录用户IP以及用户操作命令
  7. PHP学习之二:变量
  8. Vue学习笔记----基础
  9. 什么是不简单?把每一件简单的事做好就是不简单;什么是不平凡?能把每一件平凡的事做好就是不平凡。
  10. MySQL 怎么插入10天前的日期_Mysql笔记
  11. java GUI程序的编写入门
  12. 【踩坑】解决springboot注入yml配置文件 list报错
  13. 数据分析——R语言基础操作(1)-数据表示和矩阵基本操作
  14. python同时含有大写小写_如何使python同时加密大写和小写?
  15. 【BZOJ-28921171】强袭作战大sz的游戏 权值线段树+单调队列+标记永久化+DP...
  16. 准考证打印电脑记录怎么删除
  17. Xshell6、Xftp6要继续使用此程序,您必须应用最新的更新或使用新版本
  18. Android工程师级别和学习路线
  19. 我的Java开发技术总结
  20. 路由器的作用及其结构

热门文章

  1. java 构建 数字 list_数字全排列返回list的list:java实现
  2. 极兔68亿收购百世快递
  3. C++11中0与 NULL与nullptr之间的关系
  4. android 权限
  5. Video for linux 2 example (v4l2 demo)
  6. ffmpeg (四):ffmpeg, ffplay, ffprobe用法
  7. 基于C#net4.5websocket客户端与服务端
  8. linux-清除登录系统成功记录的命令
  9. 推箱子游戏的java设计思路_用JAVA实现一个推箱子游戏
  10. arcgis字段计算器无法赋值_分享∣Arcgis中62个常用技巧系列一(前20个技巧)