讲师中心 微信公众号
AI工具推荐 视频效率加速

在Java里String为什么设计成不可变_Java字符串设计原理解析

酷静大大_1145

酷静大大_1145

发布时间:2026-02-05 10:14:03

|

782人浏览过

|

来源于php中文网

原创

String不可变指内容不可修改,本质是“内容锁死”:final类、私有不可变底层数组、所有方法返回新对象;常量池共享、HashMap键稳定、多线程安全均依赖此特性。

在java里string为什么设计成不可变_java字符串设计原理解析

String不可变,本质是“内容锁死”,不是“变量锁死”

很多人看到 str = str + "a" 就以为字符串被修改了,其实只是变量 str 指向了一个新对象;原来的字符串对象(比如 "Hello")在堆里纹丝不动,哪怕没人再引用它,也得等GC来收——这才是“不可变”的真实含义。

关键实现靠三重防护:final class String 阻止继承、private final char[] value(JDK8及之前)或 private final byte[] value(JDK9+)封住底层数组引用、所有 public 方法(如 substring()、replace())全部返回新对象,绝不碰原数组一个字节。

  • 别信“final 数组就安全”这种说法:final int[] arr = {1} 仍可改 arr[0] = 2;String 安全靠的是封装 + 不暴露 value + 所有方法绕开原数组操作
  • 反射强行修改 value 是可能的(比如用 Unsafe 或 Field.setAccessible(true)),但这属于破坏 JVM 合约,生产环境严禁,且 JDK9+ 的 byte[] + 编码压缩让反射更难生效

字符串常量池(String Pool)为什么必须依赖不可变性

当你写 String a = "abc"; String b = "abc";,JVM 让 a 和 b 共享同一个对象——这省内存、提速度。但如果 "abc" 可被修改,a.toUpperCase() 一调,b 看到的就变成 "ABC",逻辑直接崩坏。

常量池不是“功能开关”,而是不可变性的必然产物:只有内容永不改变,多个引用共享才敢放心。

立即学习“Java免费学习笔记(深入)”;

Web Accessibility (WCAG 2 AA))
Web Accessibility (WCAG 2 AA))

将 WCAG 2 AA 无障碍标准应用于设计系统、UI 组件和网页——通过可运行的验证器进行对比度计算,采用设计 token 模式使颜色天生可访问,设定排版和焦点状态规则,并提供语义检查清单。适用于构建或审查 UI。

下载
  • 使用 new String("abc") 会绕过常量池,在堆里新建对象,== 比较必为 false
  • intern() 是手动“拉回”常量池的补救手段,但代价是字符串首次入池时要查表,高频调用反而拖慢性能
  • JDK7 把常量池从永久代移到堆内存后,intern() 行为更可控,但依然不建议在循环里滥用

HashMap 的 key 为什么非得用不可变对象

如果 String 可变,你把 "user" 当 key 存进 HashMap,之后又把它改成 "USER",它的 hashCode() 就变了——但 HashMap 还按旧 hash 值找桶,结果 map.get("user") 返回 null,数据“消失”了。

String 的 hashCode() 方法内部缓存了结果:private int hash,首次计算后就不再重算。这个优化只在不可变前提下成立。

  • 自定义类作 key 时,务必保证 hashCode() 和 equals() 所依赖的字段不可变,否则一样掉坑里
  • 别为了“节省对象创建”而复用 StringBuilder 拼出的字符串去当 key:虽然内容一样,但它是新对象,没问题;但若你把它转成 String 后又用反射改了内容……那就自己挖坑自己跳

多线程场景下,不可变性省掉的不是代码,是排查时间

一个 public static final String CONFIG_PATH = "/etc/app.conf" 被十个线程同时读,完全不用加锁、不用 volatile、不用 synchronized。因为没人能改它——连“改”的入口都被语言层堵死了。

换成可变对象,哪怕只读不写,你也得确认:有没有其他线程正在调用它的 setter?有没有子类偷偷覆写了行为?有没有某个工具类在背后做了 in-place 修改?

  • 类加载器用字符串定位类名(如 "java.lang.Object"),如果这段字符串中途被篡改,可能加载恶意类,这是 JVM 安全模型的基石之一
  • 日志框架中传递的 String 格式模板(如 "User {} logged in from {}")也是靠不可变性确保打印时不被并发修改导致格式错乱

真正容易被忽略的点是:不可变性不是“语法糖”,它是贯穿 JVM 内存模型、安全机制和集合设计的底层契约。一旦你开始用反射、Unsafe 或 JNI 去绕过它,后续所有基于该假设的优化(常量池、hash 缓存、线程安全共享)都会失效——而这种失效往往不会报错,只会悄悄出 bug。

热门AI工具

更多
WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

二狗PPT
二狗PPT Hot

一款AI演示文稿工具,主要用于专为中式职场打造的AI PPT生成工具,适合需要提升相关任务效率的用户。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

超级简历WonderCV

一款AI办公效率工具,主要用于免费求职简历模版下载制作,应届生职场人必备简历制作神器,适合需要提升相关任务效率的用户。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

AionClaw
AionClaw Hot

AionClaw是一款面向办公、创作和编程任务的AI桌面智能体。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

6439

2023.08.02

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

549

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

1678

2024.03.01

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

6084

2023.10.24

字符串常量的表示方法
字符串常量的表示方法

字符串常量的表示方法:1、使用引号;2、转义字符;3、多行字符串;4、原始字符串;5、字符串连接;6、字符串字面量和对象;7、编码问题。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1023

2023.12.26

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

1758

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

2724

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

6084

2023.10.24

Playwright 测试失败怎么办
Playwright 测试失败怎么办

Playwright测试失败专题汇集超时、定位器匹配、浏览器提前关闭、依赖与插件配置、文件上传、SSL及Docker启动等故障文章,并介绍通过截图、报告和Trace定位错误。

0

2026.10.21

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn