string参数传递的是引用的副本,因不可变性导致操作均创建新对象,故形参重赋值不影响实参;而stringbuilder等可变类型修改内容则会影响原对象。

面试时被问到“Java值传递机制下String作为参数的特殊表现”,关键不是背定义,而是讲清两层逻辑:String是引用类型,但它的不可变性 + 值传递机制共同导致了“看起来像值传递”的效果。直接说“String是值传递”不准确,说“String是引用传递”更错——得把底层行为拆开讲。
String参数传的是什么
传的是对象引用的副本,不是对象本身,也不是字符串内容的副本。也就是说,方法内形参和外部实参最初指向堆中同一个String对象。这点和StringBuilder、ArrayList等完全一致。
- 内存里只有一份"hello"对象,外部变量str和方法内参数s都存着它的地址(比如0x1a2b)
- 这个地址被复制了一份传进方法,所以s = 0x1a2b,str = 0x1a2b —— 初始指向相同
为什么改了没生效
不是“改不了”,而是所有String操作(+、substring、replace等)都不修改原对象,而是新建对象并让局部变量指向它。方法内重新赋值,只改变了形参这个“地址副本”的指向,不影响外部变量。
- s = s + " world" → 创建新String"hello world",地址变成0x3c4d,s现在指向0x3c4d
- str仍保持0x1a2b,继续指向原来的"hello"
- 方法结束,s变量销毁,0x3c4d若无其他引用,等待GC
对比StringBuilder就一目了然
StringBuilder可变,且没有重写引用指向逻辑,所以同样传引用副本,却能改到原对象:
- sb.append(" world") → 直接在原char[]数组末尾追加,堆中对象内容变了
- str和sb初始都指向同一块内存,sb改内容,str读出来自然也变了
- 但如果写 sb = new StringBuilder("new"),这一步也不会影响外部变量 —— 和String一样,只是改了局部引用
面试加分点:提一句常量池和intern
如果面试官追问“那用intern呢?”,可以补充:String.intern()会把字符串放入常量池并返回池中引用,但依然不改变参数传递本质。即使方法内对s调用s = s.intern(),也只是让s指向常量池里的另一个String对象,外部str不变。
本质上,String的“不可变性”是设计选择,不是语法限制;而“传参没变”是值传递 + 不可变性共同作用的结果,不是String自己搞了一套传参规则。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











