这是Java中一个很经典的问题,在stack-overflow上有不少相似的问题,然而不少回答都是错的或者回答不完整;若是你不深刻思考的话,会认为这个问题很简单,可是当你深刻下去,会发现这个问题很容易让人产生困惑。java
package simplejava; public class Q14 { public static void change(String x) { x = "cd"; } public static void main(String[] args) { String x = new String("ab"); change(x); System.out.println(x); } }
结果打印:web
C++版本以下:app
void change(string &x) { x = "cd"; }
int main(){ string x = "ab"; change(x); cout << x << endl; }
打印结果:ui
x变量存储了堆中“ab”对象的引用,当x做为一个参数传入到change()方法内部时,仍然指向堆中的“ab”对象,以下所示:spa
由于Java是按值传递的,x的值是“ab”对象的引用,当方法change()被调用时,建立了一个新的对象“cd”,而后x指向“cd”对象,以下图所示:code
这看起来像是一个完美的解释,他们很清楚Java老是按值传递的。可是,问题到底出在哪里呢?对象
上面的解释有若干处错误,为了更加容易的理解该问题,咱们仍是先理清下整个过程。blog
当字符串对象“ab”被建立的时候,Java分配了对应大小的内存空间,而后对象被赋值给变量x,事实上是x变量存储的是对象的引用,这个引用是“ab”对象在内存中的地址;内存
x变量包含了对象的引用,x并非“ab”对象,而是一个存储了“ab”对象引用(内存地址)的变量。字符串
Java是按值传递的,当x被传入change()方法的时候,事实上传入的是一个x变量的拷贝。而后在方法change()内部建立了另外一个对象“cd”,它有一个不一样的引用。真正改变的是这个x变量的拷贝,其值变成了“cd”对象的引用,而不是原始的x变量被改变;
注:感受说得有点混乱,个人理解,先说这个参数x,其至关于一个局部变量,当使用该参数的时候,将会分配一个新的存储位置,将实参拷贝到该位置,并将该拷贝值传递给该方法;
在change()方法内部,执行x = "cd"的时候,这里的x其实是main方法的x变量的一个拷贝,一开始其存放的是“ab对象”的引用,执行完这段代码后,其值变成“cd”对象的引用,而main方法的x变量并无改变,存放的仍然是“ab”对象的引用。
这个问题的缘由跟字符串的不变形没任何关系,即便将String替换成StringBuilder对象,结果仍然不变,关键点是变量存储的是对象的引用,而不是对象自己;
若是真的想改变这个对象的值,
首先这个对象是要可改变的,例如StringBuilder。
其次,咱们要保证没有新对象被建立赋值给参数变量,由于Java只能按值传递。
以下代码:
public static void main(String[] args) { StringBuilder x = new StringBuilder("ab"); change(x); System.out.println(x); }
public static void change(StringBuilder x) { x.delete(0, 2).append("cd"); }
译文连接:http://www.programcreek.com/2013/09/string-is-passed-by-reference-in-java/