Java String 对象创建与内存分配笔记

Java String 对象创建与内存分配笔记

一、核心概念:字符串常量池(Constant Pool)

  • 作用:存储字符串常量(如"abc"),实现对象共享,避免重复创建相同内容的字符串,节省内存
  • 加载时机:类加载时,字符串常量会被自动读取并放入常量池
  • 核心规则:常量池中相同内容的字符串仅存在 1 个,后续使用相同常量时直接复用,不新建

二、String 对象创建的两种方式及内存分析

方式 1:直接赋值(String s = "abc"

  • 内存过程
    1. 检查常量池:若不存在"abc",则在常量池创建 1 个"abc"对象
    2. 若常量池已存在"abc",则直接让变量s指向常量池中的该对象
  • 对象数量:仅在首次赋值时创建 1 个(常量池),后续赋值不新建对象

方式 2:new关键字创建(String s = new String("abc")

  • 内存过程(分首次和后续):
    1. 首次执行(常量池无"abc"):
      • 先在常量池创建 1 个"abc"对象(类加载时或首次遇到常量时)
      • 再在堆内存创建 1 个新的String对象(内容与常量池一致)
      • 变量s最终指向堆中的对象
      • 对象总数:2 个(常量池 1 个 + 堆 1 个)
    2. 后续执行(常量池已有"abc"):
      • 不再创建常量池对象,仅在堆内存新建 1 个String对象
      • 变量s指向堆中的新对象
      • 对象总数:1 个(仅堆中新建)

三、典型案例分析

案例 1:两次new创建相同常量

java

1
2
String a3 = new String("xyz"); // 2个对象(常量池"xyz" + 堆1个)
String b4 = new String("xyz"); // 1个对象(仅堆1个,复用常量池)
  • 总对象数:3 个(常量池 1 个 + 堆 2 个)

案例 2:字符串拼接(new String("hello") + new String("world")

  • 内存过程(共创建 6 个对象):
    1. 常量池:创建"hello""world"(2 个)
    2. 堆内存:
      • new String("hello") → 堆 1 个
      • new String("world") → 堆 1 个
      • 底层隐式创建StringBuilder对象(用于拼接)→ 堆 1 个
      • StringBuilder.toString() → 生成新的"helloworld"对象(堆 1 个,常量池无此对象
  • 关键注意:拼接结果"helloworld"仅在堆中存在,不会放入常量池

四、核心总结

创建方式 常量池对象 堆对象 总对象数(首次 / 后续)
直接赋值 String s = "a" 1 个(复用) 0 个 1 个 / 0 个
new String("a") 1 个(复用) 1 个(每次新) 2 个 / 1 个
拼接 new String("a")+new String("b") 2 个(”a”/“b”) 4 个(2 个 String + 1 个 StringBuilder + 1 个拼接结果) 6 个
  • 核心区别:==比较对象地址(常量池 vs 堆不同则为 false),equals()比较内容(相同则为 true)
  • 常量池仅存储编译期确定的字符串常量,运行时拼接结果(如new拼接)不会进入常量池