1

上篇文章说到Java的String是比较特殊的对象,它是不可变的。

有种流行的观点说String的另外一个特殊之处在于,在方法调用传参数时,String是按值传递的,其他普通对象是引用传递。

然而这种说法是大大错误的,至少是完全误解了值传递引用传递的概念。

值传递和引用传递的概念:

  • 值传递在发生的时候会为callee参数新建一个变量,新的变量存储的值与实参的值一致。
  • 引用传递时,callee并不为参数变量新建对象,而是直接使用caller里的实参变量。

举例来说:

public static void main(String[] args) {
    Object obj = new Object();
    PassValue(obj);
}

private static void PassValue(obj) {
    String s = obj.toString();
}

如果是值传递,main函数中的objPassValue方法中的o是两个独立的变量,只是他们的值相等。

如果是引用传递,main函数中的objPassValue方法中的o根本就是同一个变量。

如果文字看的有点晕,请看手画图:

Surface上画的有点抽象,包容一下。

打个比方,我要给你传递一些悄悄话,我把信息放到一个变量给你————一个txt文档。我和你之间有两种方式:

  • 你直接访问我们电脑,以后你看我电脑上的txt文档————咱俩共享变量;
  • 你也可以复制一份txt到你的电脑,以后你看你自己电脑上的那份txt文档————你和我各用各的变量。

在代码里,第一种方式就是引用传递,第二种就是值传递

还是接着例子,我给你传递的txt有可能会有两种形式:

  • 直接在txt里写着我要说的话"我看好你哟";
  • 在txt里只有一个url,url指向一个网站,网站里写着"我看好你哟".

第一种形式就是传递基本类型参数,第二张是传递引用类型参数

所以,这里有四种组合,我们一一来看:

  • 引用传递传递基本类型参数。你把txt文档里的话改为可是我并不看好你啊,我看得到,因为你改的是我电脑上的txt文档。
  • 引用传递传递引用类型参数。你直接改txt里的url地址,或者你不改url,而且去改url指向的网站的内容,我都能看到;
  • 值传递传递基本类型参数。你把txt文档里的话改为可是我并不看好你啊,我看不到,因为你改的是你电脑上的那份txt。
  • 值传递传递引用类型参数。你直接改txt里的url地址,我看不到,因为你改的是你电脑上的那份txt。你改url指向的网站的内容,我看的到。

对应代码里,当传递参数为引用类型时,例子中改url地址就是在callee中改变变量指向的堆的位置,即指向另一个对象;改url指向的内容,即是改变量指向的那个对象的内容。当传递参数为基本类型参数时,例子中改变txt文档内容,就是callee改变参数的值。

搞清楚概念了,怎么想都能把问题想明白。

回到开头的问题,有人说String特殊,特殊在哪?无非有人发现String在callee里没法被改,但是其他普通引用类型对象可以在callee里被改动。现在我们可以说,这是废话。因为String是不可变类,它的内容一经创建再不能变,别说你通过参数传递,你就是在主函数里,你照样没法改String对象的内容。所以String在callee中无法被改动和参数传递方式压根没有关系,这是String的不可变性问题,完全两码事。

可以看出来,如果参数传递的是引用变量,那么无论是哪种传递方式,callee对对象内容的改动,对caller都是可见的。除非你这对象压根不能改。

Java方法调用传参只有一种传递就是值传递。这并没有道理可讲,实现如此。

参考:
[1] https://en.wikipedia.org/wiki...


yangyangxian
9 声望0 粉丝