相信很多人听到值传递和引用传递,多多少少都会有一个疑问,为什么Java是值传递,引用数据类型也是值传递?
为什么会混淆引用数据类型和引用传递?
说白了,为什么很多人包括作者,之前都觉得java的基本数据类型是值传递,没问题,因为传入参数是一个值相同的副本,那为什么传入一个对象也是值传递呢,我们又没有创建一个新的一样的对象,这个跟引用传递和传入对象地址有区别的。
java中的传入变量无非是基本数据类型或者引用数据类型,但是处理不一样,基本数据类型只在函数内部,而引用数据类型是地址,可以通过这个地址指向堆空间中的具体对象,直接进行修改。
而我们区分开引用传递和地址修改,地址修改是指引用类型数据被传入,也就是一个地址被传入,再通过这个修改的地址指向对应的对象,进行对象的修改。
而引用传递是指直接传入一个地址,里面不存在对象和地址指向对象的引用关系,而且也不存在对象的修改。只是传入一个地址。
所以值传递就是,传值+对这个值副本+加对副本修改。
引用传递就是,传变量本身。
我们可以举个例子,当你在main函数中写下一个变量a指向一个对象,那么你传入的时候写的形参是这个a吗,不是,它只是a的副本,跟a有着相同的地址,我们可以通过这个地址去访问对象,但是传入的毕竟不是a本身。
而所谓引用传递,传的就是变量a本身,至于它指不指向别的变量或者地址或者内容或者对象,我们不关心,这种传递方式就是一种引用传递。
Java是值传递还是引用传递
值传递:函数调用时,调用者与被调用者获取的变量不是同一个变量,而是值相同的副本。
C语言是值传递。
Java继承自C语言,所以也都是值传递。
Java中的基本数据类型都是值传递,引用数据类型也是值传递,比如int都是值传递,String也是值传递。
所谓引用传递:函数调用时,调用者与被调用者指向同一个变量,对函数中的数据修改会影响原数据的值。
说回值传递,当使用"="赋值时,因为创建了相同值的副本,所以想要在函数中,对原函数数据的修改必须1.通过void变为int 让它具有返回值,并且2.用"="去接收返回值,重新赋给原数据才行。
如果不这样做会怎么样,会返回a的原值也就是18,因为从头到尾被函数操作的那个变量也就是传入参数的形参,是一个备份,仅仅是值相等。
而引用数据类型的值传递则不会,直接通过传入的副本地址对堆空间中对象进行修改,也就是只修改栈变量在堆中的地址名,改变这个变量名的指向,指向对应的对象,并不会覆盖原数据。
总结
所谓值传递和引用传递,是函数传递时备份值相等的数据,还是直接修改变量本身。
站在使用者的角度,Java中的所有传递都是值传递,都是需要备份的,值传递发生在基本数据类型,我们需要传回对应的返回数据,才能确保达到修改的效果,原因是函数内部的修改不会对外部造成影响,除非有变量指向外部的空间。最终呈现的效果就是返回值,加赋值操作(接住返回值)。
在创建引用数据类型的对象时,直接传入引用变量,系统通过变量内的地址找到实际的对象进行修改,这样不需要传回返回值。最终呈现效果就是传入的对象可以直接进行修改,所以不需要返回值,也不需要赋值,返回值可以用来干别的事情。