你真的搞懂了参数传递方式吗?(多图超详细)

15 篇文章 3 订阅
4 篇文章 0 订阅

引入

在学习编程语言的过程中,我相信大多数人都遇到或者经历过一个问题,有的时候你把变量传入了一个方法,经过方法内部的一顿操作之后,发现那个变量并没有发生变化。如果是这样也就算了,关键是有时候你传入的变量经过方法中的操作后它又发生了变化。这是啥情况?😂莫非每次向方法中传入参数都是一场豪赌吗?还是遇事不决量子力学,莫非是那股神奇的力量?😎好吧扯远了,回归正题,归根结底是因为你没有彻底的弄明白编程语言的参数传递过程

参数传递的两种方式

我相信大多数人都知道参数的两种传递方式:

  • 按值调用(call by value)
  • 按引用调用(call by reference)

这个针对大多数的编程语言是成立的,当然也有例外,例如:c++还有一个按指针传递(不过都可以按如上这两种理解)。
在很久很久之前还有一个按名调用(call by name)
不过大家放心,现在已经弃用(( •̀ ω •́ )✧ 虚晃一枪)

按值调用表示方法接收的是调用者提供的值。
按引用调用表示方法接收的是调用者提供的变量地址。

讲到这里有人可能会说这些我都知道,确实很多人都知道,但也只知道这些了,没有深入的理解,如此的话相当于还是没懂。

接下来上菜!🤞

深入理解按值调用

在这里我们以java语言为例

Java程序设计语言总是采用按值调用。也就是说,方法得到的是所有参数值的一个副本。 ------《Java核心技术 卷Ⅰ》

这句话说的相当的透彻,但是俺还是要提几句。什么是参数值?参数值就是你那个变量里面到底装的是个啥玩楞。怎么样够通俗吧😎。那么什么是副本?副本这个说法太高大上了,我们换个说法分身,这个知道吧,就是孙悟空用毫毛变的那个分身,分身终归是分身,它并不是本体

我们再合起来理解这句话,也就是说按值调用,就是把变量里面装的那个东西传到方法的形参,自己真身还在外面,自己的分身进到方法里去了。

现在我们来举个例子(为了各种语言使用者都能理解,以下使用我的自创语言,跳出三界之外,不在五行之中(●ˇ∀ˇ●)):

方法A(形参){把传进来的数加个2} //定义方法A
a = 2
方法A(a)  //把a传进方法A

a这个变量里面装的就是2,他把自己的2复制(分身),传到了方法中(可以说给了形参),这个方法是对他这个分身做出一系列操作,随着方法的执行结束,他的分身也就被五马分尸直接拜拜了,跟他的本体没有啥关系。

来张图解析一下:
在这里插入图片描述

我们都知道对于基本数据类型,变量里面装的是一个具体的结果;而对于引用数据类型,变量里面装的是地址。有些人错误的认为只要是传了个引用数据进方法,那就是按引用调用的参数传递方式。大错特错🤦‍♂️,接下来我们就看一下对于引用数据类型的值传递。

引用数据类型的按值调用

还是用我自创的语言,为大家举个例子:

方法A(形参x){对传入的对象的属性进行改动}
a = 某类的对象
方法A(a)

还记得我们的方法论吗?

按值调用,就是把变量里面装的那个东西传到方法的形参,自己真身还在外面,自己的分身进到方法里去了。

同样的我们也按照上面的方法进行理解。a变量的里面装的是对象的地址,然后a把这个地址复制一份给了形参x,这个分身进入方法中完成属性的改动。

如此一套猛如虎的操作进行下来,一看最后结果傻了眼。不是说进去的是分身,怎么a的属性变了?因为当a把自己的地址给了形参x之后,形参x也拥有了一个指向对象的指针,有了这条指针,当然可以进行改动!

看图!(〃 ̄︶ ̄)人( ̄︶ ̄〃):
在这里插入图片描述
纵使形参x在方法执行完毕之后会被回收,但是a指向的对象还在,他造成的影响也还在。

按引用调用

按引用调用,很多人第一反应,就是传地址,这没错,但是关键点在于传什么的地址。很多人不明白按引用调用的本质,就是因为这个地方没搞明白。

给你举个例子:
现在有一个变量a,里面装着某个对象的地址
在这里插入图片描述
将变量a传入方法,倘若是按引用调用,传地址,传哪个?这就是引用调用的核心!

按引用调用表示方法接收的是调用者提供的变量地址。

也就是说给形参的是那个0x1122的地址,而这个0x1122就是变量a在内存中的地址值,换句话说按引用调用相当于直接把真身放到方法中去,这回是孙悟空亲自出山,而不是他的分身了!(~ ̄(OO) ̄)ブ

还没有完全搞懂?没事👌,接下来我们通过一个证明来加深理解!

证明:在java中总是值传递

此实验参考《Java编程思想》

首先我们编写一个交换两个Employee对象的方法:

public static void swap(Employee x,Employee y){
	Employee temp = x;
	x = y;
	y = temp;
}

如果Java对对象采用的是按引用调用,那么这个方法就应该实现交换:

var a = new Employee{"Alice",·····}var b = new Employee{"Bob",······}
swap(a,b);

但是最终失败了,两者没有发生交换。

我们可以看看两种情况的内存解析图:

如果是按值调用:
在这里插入图片描述

可以看到任x、y如何乱搞,a、b都纹丝不动,所以最后的结果出来,两者是没有交换的。

如果是按引用调用:
在这里插入图片描述
可以看到如果真是按引用调用,那么两者是可以交换的。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十八岁讨厌编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值