【java】字符串存储的内存原理

1. 字符串是什么?

  • 字符串就是一段文字,比如 "Hello" 或者 "你好"

  • 在 Java 中,字符串是用 String 类型表示的。


2. 字符串的存储位置

  • 字符串在内存中的存储分为两个地方:

    1. 字符串常量池

      • 这是一个"共享区域",专门用来存放那些直接用双引号写的字符串,比如 "Hello"

      • 如果两个字符串的内容相同,它们会共享同一个内存空间,这样可以节省内存。

      • 例如:

        java

        复制代码
        String s1 = "Hello"; // "Hello" 被放入常量池
        String s2 = "Hello"; // s2 会复用常量池中的 "Hello"

        这里 s1s2 指向的是同一个 "Hello",所以 s1 == s2true

    2. 堆内存

      • 如果你用 new 关键字创建字符串,比如 new String("Hello"),那么这个字符串会放在堆内存中。

      • 堆内存中的字符串是独立的,即使内容相同,它们也是不同的对象。

      • 例如:

        java

        复制代码
        String s3 = new String("Hello"); // 在堆内存中创建一个新的 "Hello"

        这里 s3 是一个全新的对象,即使内容和 s1 相同,s1 == s3 也是 false


3. 字符串的不可变性

  • 字符串一旦创建,它的内容就不能被修改。

  • 比如:

    java

    复制代码
    String s = "Hello";
    s = s + " World"; // 这里并不是修改 "Hello",而是创建了一个新的字符串 "Hello World"
    • 原来的 "Hello" 还在内存中,新的 "Hello World" 是一个全新的字符串。

4. 为什么要用字符串常量池?

  • 节省内存

    • 如果有很多相同的字符串,比如 "Hello",它们可以共享同一个内存空间,而不是每个都单独存一份。
  • 提高性能

    • 因为字符串是不可变的,共享内存可以减少对象的创建和销毁,从而提高程序的运行效率。

5. intern() 方法的作用

  • 如果你有一个字符串是在堆内存中创建的(比如用 new),但你想把它放到字符串常量池里,可以用 intern() 方法。

  • 例如:

    java

    复制代码
    String s1 = new String("Hello"); // 在堆内存中创建
    String s2 = s1.intern(); // 把 "Hello" 放入常量池(如果池中没有)
    String s3 = "Hello"; // 复用常量池中的 "Hello"
    
    System.out.println(s1 == s2); // false,因为 s1 在堆内存,s2 在常量池
    System.out.println(s2 == s3); // true,因为 s2 和 s3 都指向常量池中的 "Hello"

6. 举个例子

假设你写了以下代码:

java

复制代码
String s1 = "Hello"; // "Hello" 被放入常量池
String s2 = "Hello"; // s2 复用常量池中的 "Hello"
String s3 = new String("Hello"); // 在堆内存中创建一个新的 "Hello"
String s4 = s3.intern(); // 把 s3 的内容放入常量池(如果不存在)

内存中的情况是这样的:

  • 字符串常量池

    复制代码
    +-------------------+
    | "Hello"           | <--- s1, s2, s4
    +-------------------+
  • 堆内存

    复制代码
    +-------------------+
    | "Hello"           | <--- s3
    +-------------------+

7. 总结

  • 字符串常量池:用来存放直接用双引号写的字符串,相同内容的字符串会共享内存。

  • 堆内存 :用来存放用 new 创建的字符串,每个字符串都是独立的对象。

  • 不可变性:字符串一旦创建,内容就不能修改,修改操作会创建新对象。

  • intern() 方法:可以把堆内存中的字符串放到常量池里。

相关推荐
碎叶城李白21 分钟前
若依学习笔记1-validated
java·笔记·学习·validated
上单带刀不带妹27 分钟前
手写 Vue 中虚拟 DOM 到真实 DOM 的完整过程
开发语言·前端·javascript·vue.js·前端框架
都叫我大帅哥1 小时前
🌊 Redis Stream深度探险:从秒杀系统到面试通关
java·redis
都叫我大帅哥1 小时前
Redis持久化全解析:从健忘症患者到记忆大师的逆袭
java·redis
程序猿阿越1 小时前
Kafka源码(一)Controller选举与创建Topic
java·后端·源码
-凌凌漆-1 小时前
【Qt】QStringLiteral 介绍
开发语言·qt
程序员爱钓鱼1 小时前
Go语言项目工程化 — 常见开发工具与 CI/CD 支持
开发语言·后端·golang·gin
程序无bug1 小时前
Spring6 当中 Bean 的生命周期的详细解析:有五步,有七步,有十步
java
二川bro1 小时前
飞算智造JavaAI:智能编程革命——AI重构Java开发新范式
java·人工智能·重构