上篇文章说到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
函数中的obj
和PassValue
方法中的o
是两个独立的变量,只是他们的值相等。
如果是引用传递,main
函数中的obj
和PassValue
方法中的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方法调用传参只有一种传递就是值传递
。这并没有道理可讲,实现如此。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。