Java中String参数传递是值传递,传递的是引用地址的副本;因String不可变,所有“修改”都创建新对象并使形参指向它,而实参仍指向原对象。

Java 中 String 在方法参数传递中确实是值传递,但这个“值”是对象引用的副本,不是对象本身,更不是原始变量本身。理解这一点,关键在于拆开两个层面:String 的不可变性 + Java 统一的值传递机制。
String 是引用类型,但传的是地址副本
String 变量在栈中存储的是堆中字符串对象的内存地址。调用方法时,这个地址被复制一份传入方法——形参获得的是原引用的副本,二者初始指向同一个字符串对象。这和 ArrayList、Person 等引用类型完全一致,不是特例。
所以,它不是基本类型的值传递(比如 int 传的是 10 这个数),而是引用类型的值传递(传的是地址这个值)。
String 的不可变性放大了“没变”的错觉
因为 String 类被声明为 final,内部 char[](或 byte[])也被封装且不可修改,所有“修改”操作(如 +、substring、replace)都必然返回一个新 String 对象。方法内一旦执行:
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- original = original + "!" → 创建新字符串,original 引用副本指向新对象
- 外部 original 引用仍指向旧对象,自然看不到变化
这不是“传值导致不能改”,而是“改的操作本身就不改原对象”,再加上引用副本重定向,双重作用下外部毫无感知。
对比 StringBuffer/Builder 就一目了然
用可变的引用类型做对照,能立刻看清机制本质:
- 传入 StringBuffer,方法内调用 sb.append("x") → 原对象内容被修改,外部可见
- 但如果写 sb = new StringBuffer("y") → 只改变副本指向,外部 sb 不受影响
这说明:只要不重新赋值引用,对对象内部状态的修改,无论 String 还是其他类型,都可通过引用副本生效;而 String 因为不可变,根本做不到“内部修改”,只能走“新建+重赋值”这条路,于是总卡在第二步失效。
想让外部 String “被更新”,得绕过引用副本限制
方法内部无法直接改变外部引用,可行方案只有两种:
- 返回新字符串:public static String update(String s) { return s + " updated"; },调用方显式接收:s = update(s);
-
用容器包装:传入 StringBuilder、AtomicReference
或自定义 Holder ,修改容器持有的引用,外部通过容器读取
硬要在方法里“改实参”而不返回或不包装,在 Java 里没有合法途径——这不是缺陷,而是语言设计的明确约束。

















