概述
首先说明结论:Java 只有值传递。
很多人对 Java 参数传递的方式不太清楚,有的认为是引用传递,有的认为是值传递。
结论大家已经看到了,Java 只有值传递。
但是,对于 Java 参数传递方式的误解确实不少。
误解
误解一:引用传递
认为 Java 是引用传递的人一般认为方法形参是对实参的引用,故应是引用传递。
误解二:传值传递
这是对值传递的一种错误认识,持这种观点的人认为,传递的参数本质上都是“值”,因此,都是值传递。
实际上,这曲解了值传递的含义,这种不存在的参数传递方式应该叫“传值传递”。
误解三:根据传递类型不同
另一种误解是,参数传递方式与参数类型有关:值类型(即基本数据类型)是值传递,引用类型是引用传递。
解析
问题的根源其实是在对“引用”的定义上。
对于 Java 而言,一个对象的地址(location)被称为“引用(reference)”。 在传递一个对象的值时,实际上是在传递它的引用。
But,这个“引用”的含义是对 Java 而言的,“引用传递”中的引用并不是这个含义。
事实上,参数传递方式描述的是参数的求值策略,主要体现在求值时间和传值方式等方面。
对于值传递和引用传递而言,都是在方法调用前求值,这方面是一致的。它们最本质的区别在于: 值传递传的是原值的副本;而引用传递传的是原值,不是副本。
因此,传值时是否产生副本才是值传递和引用传递区别的关键。
相关参数类型
明白产生了副本,Java 参数传递的行为就清晰了。
推论:由于参数是副本,因此对参数的重新赋值是不会改变原值的(与参数类型无关)。
但是,通常论及值传递的文章都会分别讨论基本数据类型和引用类型的参数。这是因为, 基本数据类型的参数传递的“内容”即是数据本身,而引用类型的参数传递的“内容”仅仅是引用(即对象的地址)。
而基本数据类型的参数被改变的方式只有一种,就是重新赋值,因此,明显不会改变原值。
但是,引用类型的参数有一点不同,它不仅可以通过重新赋值改变,还可以调用对象方法或是对对象公共属性赋值。 方法调用或公共属性赋值引起的改变会反应给原值,因为此时参数和原值指向的是同一个对象。
小结
值传递与引用传递的本质区别是是否产生副本。
无论哪种参数类型都不可以通过为其重新赋值来改变原值,但在引用类型的参数上对方法的调用或为公共属性赋值的效果会反应到原值,因为两者指向相同的对象。