模板建站教程北京网络营销方案
模板建站教程,北京网络营销方案,济源做网站公司,建设包包网站的目的目录 java 常量池详解一 静态常量池#xff08;Static Constant Pool#xff09;1.1 概述1.2 存储内容1.3 特点1.4 示例 二 运行时常量池#xff08;Runtime Constant Pool#xff09;2.1 概述2.2 存储内容2.3 特点2.4 示例 三 基础类型常量池#xff08;Primitive Type C… 目录 java 常量池详解一 静态常量池Static Constant Pool1.1 概述1.2 存储内容1.3 特点1.4 示例 二 运行时常量池Runtime Constant Pool2.1 概述2.2 存储内容2.3 特点2.4 示例 三 基础类型常量池Primitive Type Constant Pool3.1 概述3.2 存储内容3.3 特点3.4 示例3.5 JVM 参数调整缓存范围 四 字符串常量池String Constant Pool4.1 概述4.2 特点4.3 存储内容4.4 工作机制1. 字符串字面量2. String.intern() 方法 4.5 优点4.6 注意事项 五 常量池的关系与区别六 总结 java 常量池详解
在 Java JVM以 JDK 11 为例中常量池是优化内存使用和提高性能的重要机制。常量池主要包括静态常量池、运行时常量池、基础类型常量池和字符串常量池。以下将对这四种常量池进行详细整理和介绍。 一 静态常量池Static Constant Pool
1.1 概述
静态常量池是指每个 .class 文件中包含的常量池部分由 Java 编译器在编译时生成。它主要用于存储在编译期间已知的各种字面量和符号引用。
1.2 存储内容
字面量Literals 数值字面量如 int、long、float、double、char、boolean 的常量值。字符串字面量如 Hello World。 符号引用Symbolic References 类或接口的全限定名如 java/lang/String。字段的名称和描述符如 age 和 I表示 int 类型。方法的名称和描述符如 main 和 ([Ljava/lang/String;)V。
1.3 特点
编译期生成静态常量池在编译时就已经确定并存储在 .class 文件中。不可变性一旦编译完成静态常量池中的内容不可更改。类级别每个类文件对应一个静态常量池多个类文件拥有各自独立的静态常量池。
1.4 示例
假设有如下 Java 类
public class Example {private static final int CONSTANT_INT 100;private static final String CONSTANT_STRING Hello;public static void main(String[] args) {System.out.println(CONSTANT_INT);System.out.println(CONSTANT_STRING);}
}在编译后的 Example.class 文件中静态常量池会包含
整数 100字符串 Hello类 java/lang/System字段 out 和 println 方法的符号引用 二 运行时常量池Runtime Constant Pool
2.1 概述
运行时常量池是 JVM 在类加载后静态常量池的一个运行时表示。它是方法区的一部分在 JDK 8 及之后版本中属于元空间 Metaspace用于在程序运行时管理和使用常量。
2.2 存储内容
来自静态常量池的内容 字面量如数值、字符串。符号引用解析后的直接引用如指向内存地址的指针。 动态生成的内容 通过 String.intern() 方法动态添加的字符串。动态语言的元数据如在 JVM 上运行的动态语言。
2.3 特点
动态性可以在运行时动态添加新的常量如通过 intern() 方法。内存位置在 JDK 8 及之后版本中运行时常量池位于堆内存的元空间中。生命周期与类的生命周期相关类被卸载时常量池也会被回收。
2.4 示例
public class RuntimePoolTest {public static void main(String[] args) {String str1 Hello; // 静态常量String str2 new String(Hello).intern(); // 动态添加到运行时常量池}
}在上述代码中
Hello 是编译时的字符串字面量已存在于静态常量池。str2 通过 intern() 方法将 Hello 的引用添加到运行时常量池。 三 基础类型常量池Primitive Type Constant Pool
3.1 概述
基础类型常量池主要针对 Java 中的基本数据类型如 int、long 等以及其对应的包装类如 Integer、Long 等用于优化内存使用和提高性能。
3.2 存储内容
基本数据类型的常量值 如整数 1、浮点数 3.14、字符 A、布尔值 true 等。 包装类的缓存对象 包装类如 Integer、Long、Short、Byte、Character、Boolean 提供了缓存机制存储常用的常量值。
3.3 特点 缓存机制包装类会缓存一定范围内的常量对象以减少内存开销和提升性能。 范围限制 Integer 和 Long默认缓存范围是 -128 到 127。Short 和 Byte所有值都在缓存范围内。Character缓存范围是 \u0000 到 \u007F即 0 到 127。Boolean只有 true 和 false 两个值被缓存。 可调整性某些包装类的缓存范围可以通过 JVM 参数进行调整如 Integer 的缓存上限。
3.4 示例
public class PrimitiveConstantPoolTest {public static void main(String[] args) {Integer a 127;Integer b 127;Integer c 128;Integer d 128;System.out.println(a b); // true引用同一个缓存对象System.out.println(c d); // false超出缓存范围创建新对象}
}在上述代码中
a 和 b 都被自动装箱为 Integer 类型且值在缓存范围内因此引用同一个对象。c 和 d 的值超出默认缓存范围因此分别创建了不同的对象。
3.5 JVM 参数调整缓存范围
对于 Integer可以通过以下 JVM 参数调整缓存上限
-Djava.lang.Integer.IntegerCache.high1000这会将 Integer 的缓存范围扩展到 -128 到 1000。 四 字符串常量池String Constant Pool
4.1 概述
字符串常量池是 JVM 中专门用于存储字符串字面量和通过 intern() 方法添加的字符串的区域。其主要目的是为了优化字符串的存储避免重复创建相同内容的字符串对象从而节省内存并提高性能。
4.2 特点
位置 JDK 7 及之后版本字符串常量池位于堆内存中作为普通对象的一部分。JDK 6 及之前版本字符串常量池位于方法区永久代 PermGen。 唯一性 常量池中的每个字符串都是唯一的。如果两个字符串内容相同常量池中只存储一个实例。 动态性 可以在运行时通过 String.intern() 方法动态添加新的字符串到常量池中。
4.3 存储内容
字符串字面量如 Hello、World 等。通过 intern() 方法添加的字符串。
4.4 工作机制
1. 字符串字面量
当创建字符串字面量时JVM 会
检查常量池首先检查字符串常量池中是否已存在相同内容的字符串。引用或添加 如果存在直接引用常量池中的字符串。如果不存在将该字符串添加到常量池中。
示例代码
public class StringPoolTest {public static void main(String[] args) {String str1 Hello;String str2 Hello;System.out.println(str1 str2); // 输出 true引用同一个对象}
}2. String.intern() 方法
功能将字符串对象的引用添加到常量池中并返回常量池中的引用。行为 如果常量池中已存在相同内容的字符串则返回该引用。如果不存在则将当前字符串添加到常量池中并返回其引用。
示例代码
public class StringInternTest {public static void main(String[] args) {String str1 new String(Hello);String str2 str1.intern();String str3 Hello;System.out.println(str1 str2); // 输出 falsestr1 在堆中str2 引用常量池System.out.println(str2 str3); // 输出 truestr2 和 str3 引用同一常量池中的字符串}
}4.5 优点
节省内存相同内容的字符串只存储一个实例减少内存开销。提高性能字符串比较操作更高效因为可以直接比较引用。
4.6 注意事项
避免滥用 intern() 频繁调用 intern() 可能导致常量池中过多的字符串增加内存压力和 GC 负担。 字符串拼接的优化 编译时拼接如 Hello World 会在编译时优化为 HelloWorld直接引用常量池中的字符串。运行时拼接如使用 StringBuilder 进行动态拼接结果字符串默认不在常量池中需显式调用 intern() 才会被添加。
示例代码
public class StringConcatTest {public static void main(String[] args) {String str1 Hello World; // 编译时优化为 HelloWorldString str2 HelloWorld;System.out.println(str1 str2); // 输出 trueString str3 Hello;String str4 str3 World; // 运行时拼接String str5 HelloWorld;System.out.println(str4 str5); // 输出 false}
}五 常量池的关系与区别
下表总结了静态常量池、运行时常量池、基础类型常量池和字符串常量池的主要区别与联系
特性静态常量池运行时常量池基础类型常量池字符串常量池定义位置.class 文件中JVM 的方法区JDK 8 及后为元空间运行时常量池的一部分堆内存中的专用区域生成时间编译时类加载时和运行时编译时和运行时编译时和运行时存储内容字面量、符号引用静态常量池的内容及运行时生成的新常量基本数据类型的常量值及包装类的缓存对象字符串字面量及通过 intern() 添加的字符串是否可变不可变可动态扩展基本类型常量不可变包装类缓存可复用对象可通过 intern() 动态添加内存管理与类文件生命周期一致与类的生命周期一致受垃圾回收影响缓存对象存储在堆中受垃圾回收管理存储在堆中受垃圾回收管理主要优化目的减少重复字面量和符号引用的存储管理类加载时的常量支持动态常量的添加减少包装类对象的创建提升性能减少重复字符串对象的创建节省内存 六 总结
在 Java JVM 中常量池机制通过不同类型的常量池静态常量池、运行时常量池、基础类型常量池和字符串常量池优化了内存使用和性能
静态常量池在编译时确定存储类级别的常量和符号引用存在于每个 .class 文件中。运行时常量池在类加载后静态常量池的运行时表示可以动态添加常量位于方法区或元空间中。基础类型常量池针对基本数据类型和其包装类提供缓存机制减少对象创建提高性能。字符串常量池专门用于存储字符串字面量和通过 intern() 添加的字符串确保字符串唯一性节省内存。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/90092.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!