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

别再乱用 String 了!底层原理、常量池、拼接陷阱全解析

做java开发,String是每天都在用的类,但是绝大部分人只停留在只会写、只会赋值,底层还不是很了解,很多人都有这样的疑惑:

  • 明明都是"abc",为什么==有时候相等、有时候不相等?
  • String 到底是不是可变的?为什么都说它不可变?
  • 循环里字符串拼接为什么不建议用+
  • String、StringBuilder、StringBuffer 到底该怎么选?
  • new String () 会创建几个对象?常量池到底有什么用?

一、什么是String?

String就是字符串,属于引用数据类型,但是用法很像基本数据类型,都可以直接赋值。

有三种创建String类型数据的方式:

1.直接用字符串赋值。

2.使用new String(),传字符串。

3.使用new String(),传字符数组。

很多人只会这么写,但不知道内存、常量池、底层结构差别巨大。

二、核心重点:为什么String是不可变的?

1.什么是不可变的?

字符串一旦建立,在这个字符串的基础上拼接和修改都是创建一个新的对象进行修改的。这里指的都是字符串不可变,但是String变量可以指向新的字符串,原来的字符串只是没有变量引用而已,依旧没有改变。

2.底层原理

JDK1.9 之前底层是private final char[ ]value

JDK1.9 之后优化为private final byte[ ] value

  • final:数组引用不能改
  • private:外部拿不到数组,改不了里面字符

所以对象本体内容 彻底无法修改。能变的只有外面的引用变量

3. 设计成不可变的好处

  1. 字符串常量池可以缓存复用,节省大量内存;
  2. 线程安全:不可变对象天然多线程安全;
  3. 哈希值固定,适合做 HashMap 键;
  4. 作为参数传递时更安全,不会被意外篡改。

三、字符串常量池(面试常问)

1.字面常量赋值:

String s1 = "java";

String s2 = "java";

System.out.println(s1 == s2); //true

通过==比较两个引用,比较的是在内存中的地址,输出结果是true,说明是s1和s2两个引用指向的是同一个字符串对象。

这说明通过字符串给引用变量赋值是要在常量池中寻找是否有此字符串常量

有:直接引用

无:现在常量池中创建这个字符串常量再引用

总之,只要是通过字符串常量赋值,指向的都是同一个字符串。这与Integer不一样,Integer只有部分值(0 - 127)是直接指向已有对象,超过区间是建立新的对象。

2.new String( )创建

  1. 先在常量池看有没有相同的字符串常量,没有就创建;
  2. 再在堆内存创建一个新 String 对象;
  3. 引用指向堆里的对象。所以地址不一样,==是 false。

3. 经典问题:new String ("abc") 创建几个对象?

  • 常量池没有:2 个(常量池 1 个 + 堆 1 个)
  • 常量池已有:1 个(只在堆创建)

四、字符拼接

1.普通拼接

String s = "a" + "b" + "c";

编译期会直接优化成String s = new String("abc"),放入常量池,效率很高。

2.循环拼接

String str = "";

for (int i = 0; i < 1000; i++) {

str += i; }

每一次+=都会生成新的 String 对象,大量创建废弃对象,浪费内存、效率极低。

循环拼接字符串,一律用 StringBuilder

  • 常量、少量拼接 →String
  • 单线程循环拼接 →StringBuilder
  • 多线程共享拼接 →StringBuffer

http://www.jsqmd.com/news/773013/

相关文章:

  • 2026年5月国内正规市场地位证明机构实测排行与能力解析 - 速递信息
  • 2026年最新市场地位认证技术维度解析与专业机构能力评估 - 速递信息
  • 使用OpenClaw构建AI智能体时配置Taotoken作为提供商
  • MPC-BE开源媒体播放器技术架构深度解析
  • ros2 从零开始19 使用 Node Interfaces 模板类(C++)
  • 2026 年孟德尔·格林伯格分享 OurCar 开发经验:解决家庭共享汽车难题!
  • QQ自定义在线状态改在线源码
  • FastAPI 静态文件
  • 【2026实战】双栈协同:Python+Go混合架构完整实战
  • 解密TlbbGmTool:如何高效管理天龙八部单机版游戏数据的3个核心问题
  • XSLT 实例
  • VS3000芯片深度体验:除了传4K,它的USB和网络功能在视频会议里到底有多香?
  • 高频脉冲电源选购:高性价比靠谱产品筛选策略解析
  • Java 代码质量度量指标:评估代码质量的标准
  • FastAPI 安全认证
  • ComfyUI Manager:AI绘画插件的智能管家,5分钟打造高效创作环境
  • Fast-GitHub加速插件:3步解决国内GitHub访问难题的终极方案
  • 全面解决Kohya_ss安装问题的10个专业技巧:从环境配置到高效训练
  • runprompt:基于Dotprompt格式的命令行LLM提示词工程化与自动化工具
  • Botty终极指南:5步配置暗黑2重制版24小时自动化MF脚本
  • 读源码像读小说?试了 DeepWiki 和 Zread,我再也不想裸读 GitHub 了
  • Moodle自动化工具:零配置API客户端与AI助手集成实战
  • 终极ComfyUI-Manager完全指南:快速部署与高效管理自定义节点
  • Java后端面试:核心基础考点,String、StringBuilder、StringBuffer 区别详解
  • 别再死记硬背了!用Verilog手把手带你理解CRC校验的电路核心(附串行/并行实现代码)
  • 节后系统恢复中的技术操作:批量处理、数据一致性与人机协作
  • 做了一个 App Store 全球最低价查询工具:支持 App、订阅和内购价格对比
  • 打卡信奥刷题(3225)用C++实现信奥题 P8370 [POI 2001 R3] Goldmine
  • 2026年郑州装修公司推荐排名前十强,口碑好性价比高的靠谱公司盘点 - 速递信息
  • 本土化赋能:Gitee如何重塑中国开发者的代码托管体验