Java中所有参数传递均为值传递,不可变对象(如String、Integer)传的是引用地址副本,因对象不可修改,“修改”实为创建新对象,原引用不受影响,表现出强隔离性。

Java 中所有参数传递都是值传递,不可变对象(如 String、Integer、LocalDateTime 等)也不例外——传的是引用地址的副本,但因对象本身不可修改,导致“改”的行为实际是新建对象,原引用完全不受影响。这种组合让不可变对象在方法调用中表现出极强的隔离性。
不可变对象的“值传递”表现最直观
由于不可变对象禁止内部状态变更,任何看似“修改”的操作(如 str.concat()、i++、s.replace())都会返回一个新对象,而原引用变量仍指向旧对象。方法内对形参的重新赋值,只改变局部栈变量的指向,不影响外部实参。
-
String 示例:外部
String s = "a"传入方法后,方法内写s += "b",结果是形参s指向新字符串"ab",外部s仍是"a" -
Integer 示例:外部
Integer x = 100,方法内执行x++,本质是x = Integer.valueOf(x.intValue() + 1),形参换新对象,外部x不变 -
关键验证点:打印
System.identityHashCode()可确认:方法前后外部变量的 identity hash 值不变,而方法内形参的该值很可能已变
为什么不能靠“改形参”来更新外部不可变对象
因为不可变对象没有提供 setXXX() 类方法,你无法通过形参去修改其字段;而所有“操作方法”都返回新实例。即使你把形参重新赋值为新对象,也只是修改了方法栈帧里那个局部引用变量的值,它和调用方栈帧中的原始引用变量在内存上完全独立。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- 方法签名
void process(String s)中的s是一个独立的局部变量,初始时存着和外部相同的地址值 -
s = s + "x"后,s的值(即地址)被替换成新字符串的地址,但外部变量没参与这次赋值 - 这和
StringBuilder不同——后者可变,append()直接改堆中同一对象内容,外部可见
正确应用方式:靠返回值或容器封装
要让方法对外部不可变对象产生“更新效果”,必须显式传递变化结果。常见做法有三种:
立即学习“Java免费学习笔记(深入)”;
-
返回新对象:将方法改为
String process(String s),调用方用s = process(s)主动更新引用 -
使用可变容器包装:传入
AtomicReference<string></string>或自定义 holder 类(如class StrHolder { String value; }),方法内改holder.value = ... -
批量处理统一返回:如工具类中
static List<string> uppercaseAll(List<string> list)</string></string>,不修改原集合,而是返回新列表
设计启示:不可变 + 值传递 = 安全与清晰
Java 有意让 String 和包装类不可变,并配合值传递机制,天然支持线程安全、缓存优化(如字符串常量池)、函数式编程风格。你在方法间传递它们时,无需担心被意外篡改,也无需手动克隆——值传递本身已保证了引用层面的隔离。
- 多线程环境下,多个方法同时接收同一个
String参数,各自操作互不干扰 - 作为 Map 的 key 时,因内容不会变、哈希值稳定,避免了重哈希风险
- 调试时容易追踪:只要没用
return或容器,外部变量就一定保持原值

















