深度剖析Java常量池

article/2025/9/24 0:18:27

Class常量池

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

一个Class文件的16进制大体结构如下图:

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

         对于我们java程序员一般不会人工解析这种字节码文件,我们可以通过javap命令生成更可读的JVM字节码指令文件:javap -v Math.class,红色的框就是class常量池信息,常量池中主要存放两大类常量:字面量和符号引用。

字面量:

        指由字母、数字等构成的字符串和数值常量,字面量只可以右值出现,

例如:int a=1 这里a为左值,1为右值,1就是字面量。

符号引用:

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

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

例如:int a=1 ;a就是字段名称,就是一种符号引用。

运行时常量池

        只有到运行时被加载到内存后,这些符号才有对应的内存地址,那么这些常量池一旦被装入内存就变成运行时常量池,对应的符号引用会转变为被加载到内存区域的代码的直接引用,也就是我们说的动态链接。

字符串常量池

字符串常量池的位置

  •  jdk1.6及之前,有永久代,运行时常量池在永久代,运行时常量池包含字符串常量池。
  • jdk1.7:有永久代,但是已经逐步“去永久代”,字符串常量池从永久代里的运行时常量池分离到堆里。
  • jdk1.8及以后:无永久代,运行时常量池在元空间,字符串常量池依然在堆里。

用一个程序证明字符串常量池在哪里:

运行结果:

  • jdk7及以上:Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
  • jdk6Exception in thread "main" java.lang.OutOfMemoryError: PermGen space

字符串常量池设计原理

        字符串常量池底层是hotspot的c++实现的,类似一个HashTable,保存的本质上是字符串对象的引用。看下面的代码创建了多少个String对象?

1、在JDK1.6中,调用intern()首先会在字符串池中寻找equal()相等的字符串,例如字符串存在就返回该字符串在字符串池中的引用;假如字符串不存在,虚拟机会重新在永久代创建一个实例,将StringTable的一个表项指向这个新创建的实例:

 2、在JDK1.7及以上版本,由于字符串不在永久代了,intern()做了一些修改,更方便的利用堆中的对象。字符串存在与jdk1.6一样,但是字符串不存在时不再需要重新创建实例,可以直接指向堆上的实例。

        由上面两个图,可以理解为什么jdk1.6字符串池溢出会抛出OutOfMemoryError:PermGen space,而在jdk1.7及以上版本抛出OutOfMemoryError:Java heap space.

String常量池的几种例子解析:

 实例1:

String s0="zhigan";

String s1="zhigan";

String s2="zhi" + "gan";

System.out.println( s0==s1 ); //true  

System.out.println( s0==s2 );true

分析:因为例子中的s0和s1中的“zhigan”都是字符串常量,他们在编译期就被确定了,所以s0=s1为true;而“zhi”和“gan”也都是字符串常量,当一个字符串由多个字符串常量连接而成时,它自己肯定也是字符串常量,所以s2同样在编译期被优化为一个字符串常量“zhigan”,所以s2也是常量池中的“zhigan”的一个引用,所以我们得出s0==s1==s2.

实例2:
String s0="zhigan";
String s1=new String("zhigan");
String s2=“zhi”+new String("gan");
System . out . println ( s0 == s1 ); // false
System . out . println ( s0 == s2  ); // false
System . out . println ( s1 == s2  ); // false
分析:用new String()创建的字符串不是常量,不能在编译期就确定,所用用new String()创建的字符串不放入常量池中,它们有自己的地址空间。s0还是常量池中"zhigna"的引用,s1因为无法在编译期确定,所以是运行时创建的新对象"zhigan"的引用,s2因为有后半部分new String("gan")所以也无法在编译期确定,所以也是一个新创建对象"zhigan"的引用。
实例3:
String a="a1";
String b="a"+1;
System . out . println ( a == b ); // true
String a="atrue";
String b="a"+"true";
System . out . println ( a == b ); // true
String a="a3.4";
String b="a"+3.4;
System . out . println ( a == b ); // true
分析:JVM对于字符串常量的"+"号连接,将在程序编译期,JVM就将常量字符串的"+"连接优化为连接后的值,故上面的程序最后的结果都为true.
实例4:
String a="ab";
String bb="b";      
String b="a"+bb;
System . out . println ( a == b ); // false
分析:JVM对于字符串引用,由于字符串的"+"连接中,有字符串引用存在,而引用的值在程序编译期是无法确定的,即"a"+bb无法被编译器优化,只有在程序运行期来动态分配并将连接后的新地址赋给b,所以上面的结果为false.(如果bb是一个方法的返回结果,同样的原因)
实例5:
String a="ab";
final String bb="b";      
String b="a"+bb;
System . out . println ( a == b ); // true
分析:和例4中唯一不同的是bb字符串被final修饰,对于final修饰的变量,它在编译期被解析为常量值的一个本地拷贝存储到自己的常量池或嵌入到他的字节码流中,所以此时的"a"+bb和"a"+"b"效果是一样的,故结果为true.
实例6:
String s = "a" + "b" + "c" ; // 就等价于 String s = "abc";
String a = "a" ;
String b = "b" ;
String c = "c" ;
String s1 = a + b + c ;
分析:s1这个就不一样,可以通过观察器JVM指令码发现s1的"+"操作会变成如下:
StringBuilder temp=new StringBuilder();
temp.append(a).append(b).append(c);
String s=temp.toString();

八种基本类型的包装类和对象池

        java中基本类型的包装类的大部分都实现了常量池技术,严格来说应该叫对象池,再堆上,这些类是Byte,Short,Integer,Long,Character,Boolean,另外两种浮点数类型的包装类则没有实现。另外 Byte,Short,Integer,Long,Character这5种整型的包装类也只是在对应值小于等于127时才可使用对象池,也即对象不负责创建和管理大于127的这些类的对象。因为一般这种比较小的数用到的概率相对较大。

例子截图如下:

 补充:Integer a=12;底层实际上是执行了Integer.valueOf(12),里面用到了IntegerCache对象池


http://chatgpt.dhexx.cn/article/COsKZuMH.shtml

相关文章

Java常量池

Java常量池 一.相关知识 1.何为常量 第一种常量:是一个值,我们将这个值本身称为常量。比如: 整型常量:1024 实型常量:1.024 字符常量:g c w 字符串常量:"gcw" 逻辑常量:t…

Java 常量池

常量池分为 Class 常量池常量池、运行时常量池、字符串常量池。 1、 Class 常量池常量池(静态常量池) Java 文件被编译成 Class 文件,Class 文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项就是 Class 常量池&am…

JAVA常量池,一篇文章就足够入门了。(含图解)

前言 一直在《深入理解JVM》对常量池只有一个浅薄的了解,之前也遇到过这种题目,今天还是要挑出来进行一次全方位的了解。 常量池分类 常量池大体可以分为:静态常量池,运行时常量池。 静态常量池 存在于class文件中&#xff0c…

基于Elman神经网络的刀具剩余使用寿命预测(初学者+matlab代码实现)

1.Elman介绍 Elman神经网络是 J. L. Elman于1990年首先针对语音处理问题而提出来的,是一种典型的局部回归网络( global feed forward local recurrent)。Elman网络可以看作是一个具有局部记忆单元和局部反馈连接的递归神经网络 它的主要结构是前馈连接, 包括输入层、…

通过模拟退火改进的Elman神经网络(Matlab代码实现)

目录 💥1 概述 📚2 运行结果 🎉3 参考文献 👨‍💻4 Matlab代码 💥1 概述 神经网络是一个庞大的体系和概念,根据处理信息的不同方式来区分不同的network。比如根据处理信息结果的传递方向&am…

基于遗传算法优化的Elman神经网络数据预测-附代码

基于遗传算法优化的Elman神经网络数据预测 - 附代码 文章目录 基于遗传算法优化的Elman神经网络数据预测 - 附代码1.Elman 神经网络结构2.Elman 神经用络学习过程3.电力负荷预测概述3.1 模型建立 4.基于遗传优化的Elman网络5.测试结果6.参考文献7.Matlab代码 摘要:针…

【预测模型-ELAMN预测】基于海鸥算法优化ELMAN神经网络实现数据回归预测

1 简介 风能,作为一种重要,有潜力,无污染,可再生、可持续的能源,已经成为全球发电最为迅速的能源之一,越来越受到世界各国的青睐。近年来,为缓解能源短缺问题,改善环境,实现经济乃至人类的可持续发展,世界各国纷纷大力发展风能资源。然而,在实际操作中,风能固有的波动性和间歇…

MATLAB神经网络应用之Elman神经网络

Elman神经网络通常由输入层、隐含层和输出层构成,它存在从隐含层的输出到隐含层输入的反馈。这种反馈连接的结构使得被训练后不仅能识别和产生空域模式,还能够识别和产生时域模式,在此只介绍创建Elman网络的newelm函数,该函数用于…

基于粒子群算法优化的Elman神经网络数据预测-附代码

基于粒子群算法优化的Elman神经网络数据预测 - 附代码 文章目录 基于粒子群算法优化的Elman神经网络数据预测 - 附代码1.Elman 神经网络结构2.Elman 神经用络学习过程3.电力负荷预测概述3.1 模型建立 4.基于粒子群优化的Elman网络5.测试结果6.参考文献7.Matlab代码 摘要&#x…

elman神经网络的实现

在看文章时,一篇文章提到了使用elman神经网络来对癫痫病人的脑电信号与正常人的脑电信号进行区分,并且取得了较好的分类结果。于是就想自己写一个elman神经网络demo看看效果。 elman神经网络和感知机的差别通过下面的图片可以很明显的看出哪里不一样&am…

【预测模型-ELAMN预测】基于遗传算法优化ELMAN神经网络实现数据回归预测matlab代码

1 简介 风能,作为一种重要,有潜力,无污染,可再生、可持续的能源,已经成为全球发电最为迅速的能源之一,越来越受到世界各国的青睐。近年来,为缓解能源短缺问题,改善环境,实现经济乃至人类的可持续发展,世界各国纷纷大力发展风能资源。然而,在实际操作中,风能固有的波动性和间歇…

【预测模型】基于Elman神经网络预测电力负荷matlab代码

​1 简介 为提高甘肃电网负荷预测精度,提出了一种基于神经网络的负荷预测方法.针对甘肃电力系统负荷数据的非线性和动态特性,在多层前向BP网络中引入特殊关联层,形成有"记忆"能力的Elman神经网络,从而可以映射系统的非线性和动态特性.在网络训练算法中,采用自适应学…

粒子群算法优化BP和Elman神经网络-matlab源码

粒子群优化算法是一种智能优化算法,又称微粒群算法,它通过模拟自然界鸟群捕食和鱼群捕食的过程。通过群体中的协作寻找到问题的全局最优解。 收敛性的数学证明帮助了PSO的发展和应用,但此内分析具有很大的局限性。为PSO加入正交学习后&#…

基于鲸鱼算法优化的Elman神经网络数据预测-附代码

基于鲸鱼算法优化的Elman神经网络数据预测 - 附代码 文章目录 基于鲸鱼算法优化的Elman神经网络数据预测 - 附代码1.Elman 神经网络结构2.Elman 神经用络学习过程3.电力负荷预测概述3.1 模型建立 4.基于鲸鱼优化的Elman网络5.测试结果6.参考文献7.Matlab代码 摘要:针…

基于小波Elman神经网络的短期风电功率预测

风力发电在全球范围内快速发展,装机容量逐年增加,截止2013 年底,中国风电新增装机容量约 16.1GW,较 2012 年的 12.96GW 大幅提高了 24%,中国风电累计装机已超过 90GW。 风力发电并网运行是实现大规模风能发利用的有效途径。但是与常规能源不…

基于灰狼算法优化的Elman神经网络数据预测

基于灰狼算法优化的Elman神经网络数据预测 - 附代码 文章目录 基于灰狼算法优化的Elman神经网络数据预测 - 附代码1.Elman 神经网络结构2.Elman 神经用络学习过程3.电力负荷预测概述3.1 模型建立 4.基于灰狼优化的Elman网络5.测试结果6.参考文献7.Matlab代码 摘要:针…

Elman神经网络

newelm()函数: clear ; close all; clc %原始数据 data[0.4413,0.4707,0.6953,0.8133;...0.4379,0.4677,0.6981,0.8002;...0.4517,0.4725,0.7006,0.8201;...0.4557,0.4790,0.7019,0.8211;...0.4601,0.4811,0.7101,0.8298;...0.4612,0.4845,0.7188,0.8312;...0.4615,…

Elman神经网络与自适应共振网络(ART)

这几天在回过头看一些比较基础的东西,发现了两个早期研究的神经网络,Elman与ART网络,类似于上世纪80年代的hopfield神经网络,BM/RBM/DBN,RBF,SOM,以及同时期的SVM算法等等,虽然那个时…

Elman神经网络原理

Elman神经网络 近期开题,阅读到了一篇文章关于故障诊断的,其中用到了Elman神经网络,具体是结合EMD、PCA-SOM的Elman的性能评估/预测故障诊断,对Elman神经网络有点陌生,网上资源也讲的特别杂,来做个汇总Int…

【神经网络第一期】Elman神经网络基本原理

1. Elman神经网络概述 根据神经网络运行过程中的信息流向,可将神经网络可分为前馈式和反馈式两种基本类型。前馈式网络通过引人隐藏层以及非线性转移函数可以实现复杂的非线性映射功能。但前馈式网络的输出仅由当前输入和权矩阵决定,而与网络先前的输出…