当前位置: 首页 > news >正文

字符串常量池String-Pool是干啥的?声明String到底new 不 new?

public class Program01
{
public static void main(String[] args)
{
01.  String a1 = "HELLO";
02.  String a2 = "HELLO";
03.  String a3 = new String("HELLO");
04.  String a4 = "HELLO";
}
}
这个java程序你能理解他的底层操作么?比如最后程序执行完毕,a4的值是什么呢?
大部分同学可能理解a4的值是个地址,但它的值(地址),和a1相同还是和a3相同呢?

前置知识点:
<1>内存包括

Java 内存(简化)
├── 栈(Stack)
│   └── 局部变量(如 a1, a2 等引用)
├── 堆(Heap)
│   ├── 普通对象(new 出来的)
│   └── 字符串常量池(String Pool)
│       └── 字面量字符串对象(如 "HELLO")
└── 方法区(元空间,Java 8+)
└── 类信息、常量池(Class Constant Pool,注意不是 String Pool)


<2> String ss = new String("ABC");
main里如果有这个声明和初始化语句的话,ss在main的栈空间存储,它的值是地址。
“ABC” 存放在堆空间里,语句里的new 算符就是为它申请空间用的。
此时请你先不要考虑"ABC"是放在堆的普通对象区域,还是字符串常量池区域

<3> 字符串常量池(String Pool)规则

  • 程序里所有使用双引号直接赋值的字符串(如 "HELLO")会在编译期放入字符串常量池(如果池中还没有的话)。
  • 再次用双引号创建相同内容的字符串时,会直接引用常量池中已有的对象。
  • 使用 new String("HELLO") 会在堆上新建一个对象,不会与常量池的对象共用地址(但构造时如果常量池没有会先放入常量池)。 

public class Program01
{
public static void main(String[] args)
{
01.  String a1 = "HELLO";
02.  String a2 = "HELLO";
03.  String a3 = new String("HELLO");
04.  String a4 = "HELLO";
}
}

对于这个程序,我们来稍微仔细分析一下程序的4条语句到底执行了什么:

Time_01
内存:初始这样的:
-------------------------------------------
stack (main的):


-------------------------------------------
heap:
普通对象:
字符串常量池String Pool:


-------------------------------------------
方法区等....其他

Time_02
当程序还没有正式运行,即在编译时刻:
编译器发现代码中的字符串字面量 "HELLO",会将其记录在 .class 文件的常量池表中。
当程序运行时,JVM 在类加载阶段会将 "HELLO" 放入运行时的字符串常量池(在堆中)。
-------------------------------------------
stack (main的):


-------------------------------------------
heap:
普通对象                         :
字符串常量池String Pool:0X3465:“HELLO”        //为"HELLO"分配了地址0X3465


-------------------------------------------
方法区等....其他

Time_03
01.  String a1 = "HELLO";
当这条语句执行,先检查堆的字符串常量池,我们发现有“HELLO” 
那么直接给a1 赋值地址:0X3465
-------------------------------------------
stack (main的):
a1=0X3465

-------------------------------------------
heap:
普通对象                         :
字符串常量池String Pool:0X3465:“HELLO”        


-------------------------------------------
方法区等....其他

Time_04
02.  String a2 = "HELLO";
依旧先检查堆的字符串常量池,我们发现有“HELLO” 
那么直接给a2 赋值地址:0X3465
-------------------------------------------
stack (main的):
a1=0X3465
a2=0X3465
-------------------------------------------
heap:
普通对象                         :
字符串常量池String Pool:0X3465:“HELLO”        


-------------------------------------------
方法区等....其他

Time_05
03.  String a3 = new String "HELLO";
先检查常量池,已有 "HELLO"(不再新建字面量对象)
但注意,毕竟new算符出现了
那么就在堆的普通区域 new 一个全新的 String 对象(假设地址 0X5789),内容也是 "HELLO",a3 指向 0X5789。

此时堆中会有两个 "HELLO" 对象:
一个在字符串常量池(0x3465)  / 一个在堆普通区域(0x5789),a3指向后者

-------------------------------------------
stack (main的):
a1=0X3465
a2=0X3465
a3=0X5789
-------------------------------------------
heap:
普通对象                         :0X5789:"HELLO"     //为"HELLO"分配了地址0X5789
字符串常量池String Pool:0X3465:“HELLO”        


-------------------------------------------
方法区等....其他

Time_06
04.  String a4 = "HELLO";
先检查常量池,已有 "HELLO"
那么直接给a4 赋值地址:0X3465

-------------------------------------------
stack (main的):
a1=0X3465
a2=0X3465
a3=0X5789
a4=0X3465
-------------------------------------------
heap:
普通对象                         :0X5789:"HELLO"
字符串常量池String Pool:0X3465:“HELLO”       

-------------------------------------------
方法区等....其他

总结

所以从整个程序运行的过程看,编译时刻和声明a3 时发生的事情比较隐藏,对我们是陌生的:

<1>编译期
Java 编译器(javac)在编译 Program01.java 成 Program01.class 时,看到代码中的字符串字面量 "HELLO",会把它记录在 .class 文件的常量池表(Class文件常量池) 中。
这不是运行时的内存,只是类文件里的一张表。

类加载时(运行前)
JVM 加载 Program01.class 时,会把类常量池中的字符串字面量 "HELLO" 放入运行时的字符串常量池(Heap 里),这时 "HELLO" 对象就已经在堆的字符串池里了(地址 0x3465)。

运行 main 时
执行到 String a1 = "HELLO"; 时,"HELLO" 已经在常量池里了(类加载时放入了),所以 a1 直接得到引用 0x3465。

<2>声明a3时
注意前置知识点提到的字符串常量池规则第3条:
使用 new String("HELLO") 会在堆上新建一个对象,不会与常量池的对象共用地址(但构造时如果常量池没有会先放入常量池)。

http://www.dtcms.com/a/582306.html

相关文章:

  • 国外时尚设计网站手机百度app免费下载
  • A100 算力底板维修技术深析:破解高密度电路修复难题
  • 国外知名平面设计网站网站制作软件都是什么
  • 奥威BI:打破数据分析的桎梏,让决策更自由
  • 电路笔记(信号):相关匹配/模板匹配 (Correlation/Template Matching) 解码 + python实现示例
  • 中国建设银行河北省门户网站网络营销渠道策略
  • 关于网站整体实现流程有哪些
  • Docker 核心技术原理(2025年演进趋势与生产实践)
  • 网站界面的版式架构做adsense对网站有什么要求
  • 【观察】洗地机销量连续三年全球第一,添可何以“洗”卷全球?
  • 网站制作泉州公司网络服务提供者接到权利人的通知后
  • 在Ubuntu中安装并配置ssh
  • 个人网站开发赚钱方向pc端自适应网站模板
  • React“组件即函数”
  • 黄冈做网站的公司哪家好企业免费自助建站系统
  • 专业的免费网站建设哪家网站留言板模板
  • 【Web SEO】前端性能优化+SEO具体实践手册
  • Unittest接口测试生成报告和日志
  • Vue3 状态管理 + Pinia
  • 2025重新出发!中小物流仓配一体化平台的技术选型建设手记
  • 记录 RTPEngine Dockerfile 的调试过程
  • 阜新网站seo做软装的网站
  • 微信公众号微网站开发中国装修网官方网站
  • 学做预算网站wordpress编辑器
  • 盲盒抽赏小程序爬塔玩法分析:技术实现 + 留存破局,打造长效抽赏生态
  • 基于springboot的学院班级回忆录的设计与实现
  • 重庆专业网站建设公司响应式框架
  • day10(11.7)——leetcode面试经典150
  • 特定网站开发个人主页网站设计
  • flink 1.20 物化表(Materialized Tables)