Simple Java—Strings and Arrays(一)String是引用传值吗?

来源:互联网 发布:淘宝与京东 编辑:程序博客网 时间:2024/06/06 18:08

Translate from String is passed by “reference” in Java

在Java中有一个经典的问题。许多相似的疑问在stackoverflow上被提出,也有许多错误或者不完全的解释被回答。如果你不思考太多,这个问题其实很简单。但是如果你深入的去思考它,你又会变得十分困惑。

1. 一段有趣而困惑的程序

public static void main(String[] args) {    String x = new String("ab");    change(x);    System.out.println(x);}public static void change(String x) {    x = "cd";}

输出结果为“ab”
在C++中,程序如下:

void change(string &x) {    x = "cd";}int main(){    string x = "ab";    change(x);    cout << x << endl;}

输出结果为”cd”

2. 疑惑

x存储着指向堆中字符串”ab”的引用。当x传给方法change()的 形参时,它仍然指向堆中的“ab”:
这里写图片描述
因为java是按值传递的,x的值是指向”ab”的引用。当方法change()执行时,创建了一个新的”cd”对象,所以现在x是指向”cd”的:
这里写图片描述
这看上去是一个非常合理的解释,非常清楚的是,Java总是按值传递的,所以,到底是哪里错了呢?

3. 这段代码到底做了什么?

上面的解释有几个错误点,为了更简单的明白它,最好简短的走一下程序的整个过程。
当字符串”ab”被创建时,Java分配了一段内存来存储这个字符串对象。然后,这个字符串对象被分配给了变量x,变量x实际上存储的是对象的“引用”,即“ab”在内存中存储的地址。
变量x包含了对字符串的引用,但x不是这个引用的本身!它是一个存储了引用(内存地址)的变量
Java只按值传递,当x传递给方法change()中的形参时,x中的值被复制了过去。当方法change()创建一个新的字符串对象”cd”时,形参有了不同的指向。注意,是形参改变了它的指向(“cd”),不是引用本身改变。
(PS:这段比较绕,意思其实就是形参本身的值被换成了cd的地址,不存在指向ab的”引用”又指向了cd)
接下来的图说明了整个过程:
这里写图片描述

4. 错误的理解

第一段代码引出的问题和“Java不变性”没有一点关系,就算String被换成了StringBuilder,结果也不会变。这个问题的关键在于了解:变量存储这引用,但变量不是引用本身!

5.问题的解决办法

如果我们真的想要改变这个对象的值,首先,这个对象应该可以被改变,例如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");}

我的总结:

  1. 最重要的一点:Java只按值传递的。
  2. 之所以String这个对象的值没有改变,是因为形参被赋值后直接修改了里面存储的内存地址,而不是原内存地址中内容
  3. 第一段代码,C++和Java的不同,按我个人理解,是因为C++是按照引用传递的。需要注意的是,引用传递和 指针传递是不同的概念,实际上,指针传递还是按值传递:C++引用传递和值传递
0 0
原创粉丝点击