String Constant Pool

一、核心概念(通俗解释)

可以把字符串常量池理解成一个「字符串缓存池」:

  • 当你创建字符串(比如 String s = "hello")时,JVM 会先去常量池里找有没有内容为 "hello" 的字符串。
  • 如果有,直接返回这个字符串的引用(相当于「复用」);如果没有,就先在常量池里创建 "hello",再返回引用。
  • 而通过 new String("hello") 创建的字符串,会在 堆内存 新建对象,同时常量池里也会创建 "hello"(如果之前没有),这也是为什么 new String 会比直接赋值多占用内存。

二、代码示例:直观理解常量池机制

java

运行

复制代码
public class StringConstantPoolDemo {
    public static void main(String[] args) {
        // 方式1:直接赋值,字符串存入常量池,复用已有对象
        String s1 = "hello";
        String s2 = "hello";
        
        // 方式2:new 创建,堆内存新建对象,常量池仍会存"hello"(若不存在)
        String s3 = new String("hello");
        String s4 = new String("hello");

        // 对比引用(== 比较对象地址,equals 比较内容)
        System.out.println(s1 == s2);       // true:s1和s2指向常量池同一个"hello"
        System.out.println(s1 == s3);       // false:s1指向常量池,s3指向堆内存对象
        System.out.println(s3 == s4);       // false:s3和s4是堆里两个不同对象
        System.out.println(s1.equals(s3));  // true:内容相同

        // intern() 方法:将堆中的字符串对象"入池",返回常量池引用
        String s5 = s3.intern();
        System.out.println(s1 == s5);       // true:s5现在指向常量池的"hello"
    }
}

三、关键知识点

  1. 存储位置

    • JDK 1.6 及之前:常量池位于 方法区(永久代)
    • JDK 1.7 及之后:常量池被移到 堆内存(更灵活,避免永久代内存溢出)。
  2. 核心方法:intern ()

    • 作用:将当前字符串对象的内容存入常量池(若不存在),并返回常量池中的引用;
    • 场景:当需要复用动态生成的字符串(比如拼接后的字符串)时,用 intern() 可优化内存。
  3. 字符串拼接的特殊情况

    java

    运行

    复制代码
    String s1 = "a" + "b";  // 编译期优化,直接等同于"ab",存入常量池
    String s2 = "ab";
    System.out.println(s1 == s2);  // true
    
    String a = "a";
    String b = "b";
    String s3 = a + b;  // 运行期拼接,会new String("ab"),存在堆中
    System.out.println(s3 == s2);  // false
    System.out.println(s3.intern() == s2);  // true

四、实际应用价值

  • 内存优化:避免大量重复字符串占用内存(比如业务中频繁使用的固定字符串,如 "success"、"fail");
  • 性能提升 :复用已有对象减少 GC(垃圾回收)压力,字符串比较时 ==equals 更快(但仅适用于常量池字符串)。

总结

  1. 字符串常量池是 JVM 优化字符串内存的缓存机制,直接赋值的字符串会优先存入常量池并复用;
  2. new String() 会在堆创建新对象,可通过 intern() 方法将内容入池复用;
  3. JDK 1.7 后常量池移至堆内存,拼接字符串的编译期 / 运行期处理逻辑不同,需注意引用对比的差异。
相关推荐
快乐肚皮2 小时前
一文了解XSS攻击:分类、原理与全方位防御方案
java·前端·xss
郝学胜-神的一滴2 小时前
OpenGL的glDrawElements函数详解
开发语言·c++·程序人生·游戏·图形渲染
白宇横流学长2 小时前
基于SpringBoot实现的历史馆藏系统设计与实现【源码+文档】
java·spring boot·后端
moxiaoran57532 小时前
Go语言结构体
开发语言·后端·golang
wearegogog1232 小时前
基于C# WinForm实现的带条码打印的固定资产管理
开发语言·c#
毕设源码-赖学姐2 小时前
【开题答辩全过程】以 高校教学资源共享系统的设计与实现为例,包含答辩的问题和答案
java·eclipse
Lvan的前端笔记2 小时前
python:深入理解 Python 的 `__name__ == “__main__“` 与双下划线(dunder)机制
开发语言·python
辣机小司3 小时前
【软件设计师】自编思维导图和学习资料分享(中级已过)
java·c++·软考·软件设计师
董世昌413 小时前
什么是扩展运算符?有什么使用场景?
开发语言·前端·javascript