Java 常量池详解(一)字符串常量池

article/2025/9/23 23:46:35

在Java的内存分配中,总共3种常量池:

Java 常量池详解(二)class文件常量池 和 Java 常量池详解(三)class运行时常量池

1.字符串常量池(String Constant Pool)

在JDK1.7之前运行时常量池逻辑包含字符串常量池存放在方法区, 此时hotspot虚拟机对方法区的实现为永久代
在JDK1.7 字符串常量池被从方法区拿到了堆中, 这里没有提到运行时常量池,也就是说字符串常量池被单独拿到堆,运行时常量池剩下的东西还在方法区, 也就是hotspot中的永久代
在JDK1.8 hotspot移除了永久代用元空间(Metaspace)取而代之, 这时候字符串常量池还在堆, 运行时常量池还在方法区, 只不过方法区的实现从永久代变成了元空间(Metaspace)

在这里插入图片描述

1.1:字符串常量池在Java内存区域的哪个位置?

  • 在JDK6.0及之前版本,字符串常量池是放在Perm Gen区(也就是方法区)中;
  • 在JDK7.0版本,字符串常量池被移到了堆中了。至于为什么移到堆内,大概是由于方法区的内存空间太小了。
  • (堆内是可以进行回收的,然后方法区也是能回收的,但是本身区域内存比较少,如果用的字符串常量太多了,也会抛java.lang.OutOfMemoryError:PermGenspace 异常)

1.2:字符串常量池是什么?

  • 在HotSpot VM里实现的string pool功能的是一个StringTable类,它是一个Hash表,默认值大小长度是1009;这个StringTable在每个HotSpot VM的实例只有一份,被所有的类共享。字符串常量由一个一个字符组成,放在了StringTable上。
  • 在JDK6.0中,StringTable的长度是固定的,长度就是1009,因此如果放入String Pool中的String非常多,就会造成hash冲突,导致链表过长,当调用String#intern()时会需要到链表上一个一个找,从而导致性能大幅度下降;
  • 在JDK7.0中,StringTable的长度可以通过参数指定:
-XX:StringTableSize=66666`

1.3 字符串常量池生成的时机?

String a = "a";

在这里插入图片描述

  • 全局字符串池里的内容是在类加载完成,经过验证,准备阶段之后在堆中生成字符串对象实例,然后将该字符串对象实例的引用值存到string pool中(记住:string pool中存的是引用值而不是具体的实例对象,具体的实例对象是在堆中开辟的一块空间存放的)
    在这里插入图片描述

如何将String对象放入到常量池

  • “abc” 双引号String 对象会自动放入常量池
  • 调用String的intern 方法也会将对象放入到常量池中

String 对象代码案例解析

public static void main(String[] args) {String a = "a";String b = "b";String c = "a" + "b";//生成两个对象 一个"ab" ,一个新的String 对象value 值是ab//public String(String original) {//   this.value = original.value;//   this.hash = original.hash;//}String d = new String("ab"); String e = a + "b";String f = a + b;String g = "ab";System.out.println(e == c);System.out.println(c == d);System.out.println(f == c);System.out.println(g == c);String e1 = e.intern();String c2 = c.intern();System.out.println(e1 == c2);System.out.println(e1 == c);
}//运行结果
false
false
false
true
true
true
  1. String c =“a” + “b” 和String c = “a” + b (String b= “b”)的区别
String b = "b";
String c = "a" + "b"; 等价于 String c ="ab"
String c1 = "a" + b; // java 反编译的结果  0 ldc #3 <b> //load constant  加载常量 "b"2 astore_1   // 存入变量1中3 ldc #4 <ab> //自动识别了 5 astore_26 new #7 <java/lang/StringBuilder>9 dup
10 invokespecial #8 <java/lang/StringBuilder.<init>>
13 ldc #2 <a>
15 invokevirtual #9 <java/lang/StringBuilder.append>
18 aload_1
19 invokevirtual #9 <java/lang/StringBuilder.append>
22 invokevirtual #10 <java/lang/StringBuilder.toString>
25 astore_3
26 return

(1) “a”+“b” 编译器自动识别了变成了 “ab” => 3 ldc #4
(2) “a” + b(变量)

  1. 先new 了StringBuilder 对象,并初始化init
  2. 然后bulider.append(“a”)
  3. 从变量1(b)中取出值"b"
  4. 然后执行了bulider.append(“b”)
  5. 最后执行了builder.toString() 方法 给变量3( c1)进行赋值

new string(“abc”)创建了几个对象

答案:是两个 ,new string(xxxx)方法,xxxx传入的是String对象。说明xxxx也是String对象。

	 public String(String original) {this.value = original.value;this.hash = original.hash;}

String 是一个final 类型对象是不会变化的,如果发生变化,说明其实是新的对象。

public final class String

解析public native String intern() 方法

如果常量池中存在当前字符串, 就会直接返回当前字符串. 如果常量池中没有此字符串, 会将此字符串放入常量池中后, 再返回

native实现代码:

  • \openjdk7\jdk\src\share\native\java\lang\String.c
Java_java_lang_String_intern(JNIEnv *env, jobject this) 
{ return JVM_InternString(env, this); 
}
  • \openjdk7\hotspot\src\share\vm\prims\jvm.h
JNIEXPORT jstring JNICALL 
JVM_InternString(JNIEnv *env, jstring str);
  • \openjdk7\hotspot\src\share\vm\prims\jvm.cpp
JVM_ENTRY(jstring, JVM_InternString(JNIEnv *env, jstring str)) JVMWrapper("JVM_InternString"); JvmtiVMObjectAllocEventCollector oam; if (str == NULL) return NULL; oop string = JNIHandles::resolve_non_null(str); //调用StringTable::intern 方法oop result = StringTable::intern(string, CHECK_NULL);return (jstring) JNIHandles::make_local(env, result); 
JVM_END
  • \openjdk7\hotspot\src\share\vm\classfile\symbolTable.cpp
oop StringTable::intern(Handle string_or_null, jchar* name, int len, TRAPS) { //根据名字找到对应hash下标unsigned int hashValue = java_lang_String::hash_string(name, len); int index = the_table()->hash_to_index(hashValue); //顺着对应的链表查找对应的值oop string = the_table()->lookup(index, name, len, hashValue); // Found if (string != NULL) return string; // Otherwise, add to symbol to table return the_table()->basic_add(index, string_or_null, name, len, hashValue, CHECK_NULL); 
}
  • \openjdk7\hotspot\src\share\vm\classfile\symbolTable.cpp
oop StringTable::lookup(int index, jchar* name, int len, unsigned int hash) { for (HashtableEntry<oop>* l = bucket(index); l != NULL; l = l->next()) { if (l->hash() == hash) { if (java_lang_String::equals(l->literal(), name, len)) { return l->literal(); } } } return NULL; 
}
1.它的大体实现结构就是:JAVA 使用 jni 调用c++实现的StringTable的intern方法。2.要注意的是,String的String Pool是一个固定大小的Hashtable,默认值大小长度是1009,如果放进String Pool的String非常多,就会造成Hash冲突严重,从而导致链表会很长,而链表长了后直接会造成的影响就是当调用String.intern时性能会大幅下降。

Interger 包装类的池化技术

public final class Integer extends Number implements Comparable<Integer> {@Native public static final int   MIN_VALUE = 0x80000000;@Native public static final int   MAX_VALUE = 0x7fffffff;//缓存-128到127的值在IntegerCache里面,可以进行共享private static class IntegerCache {static final int low = -128;static final int high;static final Integer cache[];static {// high value may be configured by propertyint h = 127;String integerCacheHighPropValue =sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");if (integerCacheHighPropValue != null) {try {int i = parseInt(integerCacheHighPropValue);i = Math.max(i, 127);// Maximum array size is Integer.MAX_VALUEh = Math.min(i, Integer.MAX_VALUE - (-low) -1);} catch( NumberFormatException nfe) {// If the property cannot be parsed into an int, ignore it.}}high = h;cache = new Integer[(high - low) + 1];int j = low;for(int k = 0; k < cache.length; k++)cache[k] = new Integer(j++);// range [-128, 127] must be interned (JLS7 5.1.7)assert IntegerCache.high >= 127;}private IntegerCache() {}}public static Integer valueOf(int i) {//是不是在-128到127里面,不是的话就生成新的Integerif (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}
}        

Integer 对象代码案例解析

public void test(){Integer i1 = 10;Integer i2 = 10;Integer i3 = new Integer(10);//新对象Integer i4 = new Integer(10);//新对象Integer i5 = Integer.valueOf(10);//从缓存池里面获取。Integer i6 = Integer.valueOf(128);Integer i7 = 128;System.out.println(i1 == i2); // trueSystem.out.println(i2 == i3); // falseSystem.out.println(i3 == i4); // falseSystem.out.println(i1 == i5); // trueSystem.out.println(i6 == i7); // false
}//运行结果:
true
false
false
true
false

为啥Integer i1 =10 跟Integer.valueOf(10) 是相等的?

  • 因为Integer i1 = 10 底层原理是 Integer i1 = Integer.valueof(10)
  //Integer i1 =10 反编译的结果0 bipush 102 invokestatic #14 <java/lang/Integer.valueOf> //调用了Integer.valueof方法5 astore_1

为啥Integer i1 =128 跟Integer.valueOf(128) 是不相等的?

  • 因为超过-128~127 这个范围,就不在缓存池里面,不能共享都是新new 出来的
public static Integer valueOf(int i) {//是不是在-128到127里面,不是的话就生成新的Integerif (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}

问题:包装类对象池是不是 JVM 常量池的一种?

  • 包装类的对象池是池化技术的应用,并非是虚拟机层面的东西,而是 Java 在类封装里实现的,IntegerCache 是 Integer在内部维护的一个静态内部类,用于对象缓存。
  • Integer 对象池在底层实际上就是一个变量名为 cache 的数组,里面包含了 -128 ~ 127 的 Integer 对象实例。使用对象池的方法就是通过 Integer.valueOf() 返回 cache 中的对象,像 Integer i = 10这种自动装箱实际上也是调用 Integer.valueOf() 完成的
  • 这和常量池中字面量的保存有很大区别,Integer 不需要显示地出现在代码中才添加到池中,初始化时它已经包含了所有需要缓存的对象

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

相关文章

Java常量池储存什么_JAVA常量池中存储的常量是什么

展开全部 我当初也存在这样一个疑问&#xff0c;下面我把e69da5e887aa3231313335323631343130323136353331333262356165当初所搜集的一些资料以及自己的理解贴出来给你看看(比较多&#xff0c;需要耐心点看&#xff0c;呵呵)&#xff1a; 理解Java常量池 JVM运行时数据区的内存…

深度剖析Java常量池

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

Java常量池

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

Java 常量池

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

elman神经网络的实现

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

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

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

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

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

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

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

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

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

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

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

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

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

Elman神经网络

newelm()函数&#xff1a; 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)

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