java参数传递机制

时间:2021-12-03 21:28:23

1.什么是参数传递机制?

所有的程序设计语言都有关于过程的概念,在c语言和其类似的语言中我们把它称为“函数”,而在java和c++这样面向对象的语言中我们把它称为“方法”(在后面的解释中,为了更好的将这些规则带入到其他语言中去,我们将之统称“过程”),java中的方法可以像函数或过程一样运行,但总和某个特定的类相关联。在调用过程中使用的参数是如何与在过程定义中使用的参数关联起来,我们把这称作参数传递,而采取什么样的参数传递机制决定了调用代码序列是如何处理参数。

2.值调用

在值调用中,会对实在参数(调用过程中使用的参数)求值或者拷贝(如果它是变量)。这些值被放在属于调用过程的相应形式参数(在过程定义中使用的参数)的内存位置上。java使用的正是这种方式,值调用的效果是,被调用过程所做的所有有关形式参数的计算都局限于这个过程,而相应的实在参数本身不会被改变。

3.引用调用

在引用调用中,实在参数的地址会作为相应的形式参数的值被传递给被调用者。在被调用者的代码中使用形式参数时,实现方法是沿着这个指针找到调用者指明的内存位置,因此改变形式参数就相当于改变了实在参数。c++里的“ref”参数就是使用的引用调用。

为什么使用引用调用呢?

因为严格的值调用要求调用者把整个实在参数拷贝到属于相应形式参数的空间上,当参数很大时,比如传递的是一个很大的字符串或者数组,拷贝的代价会很大。

4.java参数传递

java中是只使用值调用的,既然上面提到,值调用在调用时所作的计算不会影响实在参数本身,那么为什么我们在java中传递了一个对象时,却依然会像引用调用那样改变对象本身的值呢?这是因为java中的很多变量实际上是对它们所代表的事物的引用,就像c中的指针。虽然java使用值调用,但只要我们把一个对象的名字传递给一个被调用过程,那个过程收到的实际上是这个对象的引用(拷贝引用中的地址),因此在操作这个形式参数时也会通过所拷贝的地址改变这个对象本身的值。

既然如此,那么使用值调用传引用和使用引用调用传地址有什么区别?

区别很明显,当我们在使用值调用传引用时,改变的是引用所指向的对象的值,并没有改变这个引用本身所指向的地址。大家可以这样理解,假设所有的变量都有两个属性,存储的值和地址,引用实际上也是一个变量,只不过这个变量所存储的值就是一个地址而已,在值调用的时候是不能改变实在参数本身的值的(这点可以自行验证),这也印证了在值调用时你无论如何也改变不了引用指向的目标,也就是存储的地址。而在引用调用时传递的是变量本身的地址,可以改变变量存储的值。

5.慎用别名

引用调用或者其他类似的方法,比如上面提到的java所使用的把对象的引用当作值传递,会引起一个有趣的结果。有可能两个形式参数指向同一个位置,这样的变量称为另一个变量的别名,结果是,任意两个看起来从两个不同的形式参数中获得的值的变量也可能成为对方的别名。

例如:假设a是属于某个过程p的数组,且p通过调用q(a,a)调用了另一个过程q(x,y)。再假设像java那样,参数是通过值传递的,但数组名实际上是指向数组存放位置的引用。现在,x和y成了对方的别名,这时候要注意的是,如果改变x[10]=6,那么y[10]也会变成2。