Java参数均为值传递,基本类型传数值副本,引用类型传地址副本;String等不可变对象因底层final字段和操作返回新实例,确保方法内修改不影响原引用,天然线程安全且支持常量池复用。

Java 中的值传递机制和不可变对象是两个独立但高度协同的设计。理解它们的配合方式,关键在于看清“传递的是什么”和“对象本身能不能被改”这两层事实。
值传递的本质:只传副本,不传本体
Java 所有参数都是值传递:
- 基本类型(如 int、boolean):传的是数值本身的副本,方法内修改不影响外部变量;
- 引用类型(如 String、自定义对象):传的是引用的副本,即堆中对象地址的一个拷贝,不是对象本身。
也就是说,方法内部拿到的只是一个“指向对象的指针的复制品”。它能顺着这个指针读写对象内容——前提是对象可变。而 String 这类不可变对象,恰恰堵死了“顺着指针去改内容”这条路。
不可变对象如何放大值传递的安全性
String 的不可变性体现在底层:其字符数组 value 是 final 的,且所有看似修改的方法(如 substring、replace、toLowerCase)都返回新对象,而非复用原对象。
立即学习“Java免费学习笔记(深入)”;
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 即使你把一个 String 引用传进方法,方法内部也无法真正修改它——任何操作都会生成新对象;
- 原引用仍指向旧对象,调用方完全不受干扰;
- 不需要防御性拷贝(defensive copy),因为共享不会带来风险。
对比一个可变对象(比如 StringBuilder):若把它传入方法,方法里调用 append() 就会真实改变原对象内容,调用方可能意外看到副作用。而 String 天然免疫这类问题。
线程安全与共享复用的底层支撑
值传递 + 不可变性共同消除了并发场景中最常见的两类隐患:
- 多个线程同时持有同一个 String 引用,无需同步——没人能改它;
- 字符串常量池能安全复用同一实例(如 "abc"),因为 JVM 确信它的内容永远不会变;
- 作为 HashMap 的 key 时,hashCode 可缓存且永不失效,避免哈希冲突或查找失败。
这些优势不是靠加锁实现的,而是由语言层面的不可变契约保障的。
实际编码中的直观体现
看这段代码就清楚了:
void process(String s) {
s = s + "!"; // 创建新字符串,s 引用已指向新对象
System.out.println(s); // 输出 "hello!"
}
String original = "hello";
process(original);
System.out.println(original); // 仍是 "hello",未变
这里没有“传引用所以能改原值”的错觉。方法内 s 的重新赋值,只是改变了局部变量的指向,original 指向的还是原来的字符串对象——而这个对象,从创建起就没变过,也不能被变。

















