String不可变是因为其内部字符数组被声明为final,所有修改方法均返回新对象。传参传递引用副本,重新赋值只影响局部变量,原引用不变。

Java 中的 String 本身就是不可变的,你不需要、也无法通过传参方式“避免外部修改”——因为根本改不了。
为什么 String 不可变?
String 对象一旦创建,其内部的字符数组(JDK 8 及以前是 char[],JDK 9+ 是 byte[])就被声明为 final,且所有可能改变内容的方法(如 substring、toLowerCase、replace)都返回**新对象**,原对象保持不变。
例如:
String s = "hello"; s.toUpperCase(); // 返回 "HELLO",但 s 还是 "hello" System.out.println(s); // 输出:hello
传参时实际发生什么?
当你把 String 作为参数传入方法时,传递的是该字符串对象的引用副本(不是对象本身,也不是深拷贝)。但由于 String 不可变,即使方法内部对形参重新赋值,也只影响局部变量,不影响原始引用:
你是 TypeScript 项目架构专家,专注于脚手架搭建生产就绪的 Node.js 和前端应用。生成包含现代工具链(pnpm、Vite、Next.js)、类型
立即学习“Java免费学习笔记(深入)”;
void modify(String s) {
s = s + " world"; // 创建新字符串,s 指向新对象
}
String original = "hello";
modify(original);
System.out.println(original); // 仍是 "hello"
真正需要注意的“假可变”陷阱
虽然 String 不可变,但以下情况容易让人误以为它被“修改”了:
- 混淆引用赋值与内容修改:给形参重新赋值 ≠ 修改原对象
- 误用 StringBuilder / StringBuffer:它们是可变的,若传入的是 StringBuilder,外部确实能修改内容
-
反射强行修改(不推荐):通过反射可以修改 String 内部的
value数组,但这破坏 JVM 合规性,仅限研究,生产环境禁用
如果你真正想保护的是“字符串内容不被意外变更”
那只需做到:
- 坚持使用
String类型,而非可变的StringBuilder或char[] - 方法返回新字符串时,由调用方决定是否更新引用
- 若需封装敏感字符串(如密码),考虑使用
char[]并手动清空,但这是出于安全擦除目的,和“不可变性”无关
不复杂但容易忽略:String 的不可变性是语言设计保证的,不是靠传参技巧实现的。放心传,它不会变。

















