news 2026/8/26 4:01:15

Java 中的 String 类为何被设计成不可变(Immutable)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java 中的 String 类为何被设计成不可变(Immutable)

一、先搞懂:什么是 String 的不可变?

String 的不可变指的是:一旦一个 String 对象被创建,它内部的字符序列(底层是char[] value数组,Java 9 后改为byte[])就无法被修改。看似修改 String 的操作(如拼接、替换),其实都是创建了一个全新的 String 对象,原对象不会有任何变化。

简单代码示例验证不可变:
public class StringImmutableDemo { public static void main(String[] args) { String s1 = "abc"; String s2 = s1; // s2和s1指向常量池中的同一个"abc"对象 // 看似修改s1,实际是创建新对象 s1 = s1 + "d"; System.out.println(s1); // 输出 "abcd"(新对象) System.out.println(s2); // 输出 "abc"(原对象未变) System.out.println(s1 == s2); // false,指向不同对象 } }

二、String 设计为不可变的核心原因

1. 安全性(最核心原因)

String 是 Java 中最常用的类,大量用于存储敏感信息(如用户名、密码、数据库连接串、网络请求参数等),不可变设计能从根本上避免这些数据被篡改:

  • 防止参数篡改:比如方法传参时,若 String 可变,方法内部修改参数会导致外部原变量被篡改,引发难以排查的 bug;
  • 类加载安全:JVM 类加载时会通过类名(String 类型)定位类文件,若 String 可变,可能被恶意修改类名,导致加载错误的类,引发安全漏洞;
  • 哈希表安全:String 常作为 HashMap、HashSet 的 Key,若可变,修改后哈希值会变化,导致 Key 对应的 Value 无法被正确查找,甚至引发哈希表混乱。
2. 支持字符串常量池(提升性能、节省内存)

Java 为了优化内存,设计了字符串常量池(String Pool)(位于堆内存的元空间):相同的字符串字面量只会在常量池中创建一次,所有引用都指向这个对象。

  • 不可变是常量池的前提:如果 String 可变,那么修改常量池中的一个 String 对象,会导致所有引用它的变量都被篡改,这显然不符合预期;
  • 性能提升:常量池复用字符串对象,避免了频繁创建和销毁对象的开销,大幅提升内存利用率。
代码示例:常量池复用
public class StringPoolDemo { public static void main(String[] args) { // 两个字面量都指向常量池中的同一个"hello"对象 String s1 = "hello"; String s2 = "hello"; System.out.println(s1 == s2); // true,引用同一个对象 // new String会创建新对象,不复用常量池(但内部value仍指向常量池) String s3 = new String("hello"); System.out.println(s1 == s3); // false } }
3. 天生的线程安全

不可变对象的状态在创建后就固定不变,多线程并发访问时,不需要加锁(同步)就能保证数据一致性,避免了线程安全问题。

  • 比如多个线程同时读取同一个 String 对象,不用担心其中一个线程修改它的值,省去了同步锁的开销,提升并发性能。
4. 哈希值缓存(提升哈希集合性能)

String 的hashCode()方法会缓存哈希值(String 类中有一个private int hash成员变量存储哈希值):

  • 因为 String 不可变,哈希值计算一次后就不会变化,后续调用hashCode()直接返回缓存值,无需重新计算;
  • 这对 HashMap、HashSet 等依赖哈希值的集合来说,能大幅提升查找效率。
源码佐证(Java 8):
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { // 存储字符的数组,被final修饰,且没有提供修改这个数组的方法 private final char value[]; // 缓存哈希值 private int hash; // Default to 0 // 构造方法(示例) public String(String original) { this.value = original.value; this.hash = original.hash; } // hashCode方法:缓存哈希值 public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; } }

关键点:value数组被final修饰,且 String 类没有提供任何修改value的 public 方法(如 set、修改数组元素),确保了不可变性。

总结

Java 将 String 设计为不可变的核心原因可归纳为 3 点:

  1. 安全性:防止敏感数据被篡改,保障类加载、哈希表等核心功能的安全;
  2. 性能与内存优化:支撑字符串常量池复用,缓存哈希值提升集合操作效率;
  3. 线程安全:不可变特性让 String 天生支持多线程并发访问,无需同步锁。

补充:如果需要可变的字符串,Java 提供了StringBuilder(非线程安全)和StringBuffer(线程安全),它们的设计目的就是解决 String 拼接时创建大量临时对象的问题,本质是可变的字符序列。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/21 17:15:17

童乐互娱旗下厂牌闪亮登场短剧《和你分手后的第七个冬》今日上线

今日&#xff0c;童乐互娱成立的精品微短剧厂牌【闪亮登场】&#xff0c;参与制作的微短剧《和你分手后的第七个冬》于2月4日在红果平台独家上线。 这部由演员翟一莹与舒童联袂主演的剧集&#xff0c;上线前平台预约人数已突破100万&#xff0c;成为2026年开年最受期待的微短剧…

作者头像 李华
网站建设 2026/8/19 17:05:29

陈晓翻车?珠海口误背后,是戏痴的日常!

近日&#xff0c;陈晓在珠海参加活动时&#xff0c;一句对着台下观众的问候意外跑偏&#xff0c;“深圳的朋友……”脱口而出后&#xff0c;他自己先愣了一下&#xff0c;随即露出那个“哎呀说错了”的微表情&#xff0c;瞬间被镜头捕捉&#xff0c;可爱又真实。事后&#xff0…

作者头像 李华
网站建设 2026/8/25 10:27:22

从成员初始化列表开始,彻底理解 C++ 对象的一生

很多人在学习 C 类时&#xff0c;都会看到这样一段代码&#xff1a;Student(std::string n, int a) : name(n), age(a) {}第一反应通常是&#xff1a;冒号后面这串 name(n) 是什么&#xff1f; 为什么不直接在 {} 里写 name n;&#xff1f;这不是语法糖&#xff0c;它的正式名…

作者头像 李华
网站建设 2026/8/24 2:50:50

写不出大纲?保姆级教程:手把手带你搭建高逻辑毕业论文框架

最近不少学弟学妹跟我抱怨&#xff1a;“题目定好了&#xff0c;但对着电脑一下午&#xff0c;连大纲的一行字都没憋不出来。” 作为经历过几次大修、也帮不少人捋过思路的老油条&#xff0c;我必须告诉大家&#xff1a;大纲不是一个字一个字敲出来的&#xff0c;而是根据逻辑…

作者头像 李华
网站建设 2026/8/24 6:59:56

计算机PHP毕设实战-基于php+vue的课程在线考试系统的设计与实现课程管理、班级管理、题库管理【完整源码+LW+部署说明+演示视频,全bao一条龙等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华