C/C++,Java,和Javascript 值传递和引用传递的那点事
首先说说二者到底都是什么?
引用传递和值传递都是基于传参而言的。
值传递:将实参变量的值复制一份交给形参,即,现在有两个空间,实参空间和形参空间,两空间独立。值传递基本类型的变量而言。
引用传递:是对于对象型变量而言的,传递的是该变量的地址,不是对象本身。
目录
对于C语言 / C++来说
值传递:
#include <stdio.h>
void exchange(int a, int b) {
int c;
c = a;
a = b;
b = c;
}
int main() {
int a = 5;
int b = 8;
exchange(a, b);
printf("a = %d\n", a);
printf("b = %d", b);
}
输出结果
执行exchange函数的时候,将实参a和b的值传递给了形参,就是,将a和b的值各复制一份赋值给形参a和形参b的空间,所以,函数内对形参空间的操作完全不会影响到实参空间!而伴随着函数调用的结束,形参空间和其内的局部变量将会被释放。
引用传递:
C语言没有引用传递,看到很多博文都错把指针传递当做引用传递,只有C++中才存在引用传递
#include <iostream>
using namespace std;
int main()
{
void fun(int x,int y); // C++值传递
void fun1(int& x,int& y); // C++引用传递
int x=1,y=2;
fun(x,y);
cout<<x<<endl<<y<<endl;
fun1(x,y);
cout<<x<<endl<<y<<endl;
return 0;
}
void fun(int x,int y){
x=3;
y=4;
}
void fun1(int& x,int& y){
x=5;
y=6;
}
运行结果
引用传递的形参加了一个&符号,这个形参相当于实参的一个别名,对形参的操作都相当于对实参的操作。
指针传递:也称地址传递
#include <stdio.h>
void exchange(int *a, int *b) {
int c;
c = *a;
*a = *b;
*b = c;
}
int main() {
int a = 5;
int b = 8;
exchange(&a, &b);
printf("a = %d\n", a);
printf("b = %d", b);
}
运行结果
很明显,指针传递(地址传递)和引用传递(C++)才能改变实参的值,值传递无法改变实参的值
对于Java来说
Java中参数是用何种传递呢?举个例子,还是两个数交换
值传递
public static void exchange(int a, int b) {
int tmp = a;
a = b;
b = tmp;
}
public static void main(String[] args) {
int a = 3;
int b = 4;
exchange(a, b);
System.out.println(a);
System.out.println(b);
}
运行结果
3
4
方法调用时,实参把它的值传递给对应方法的形参,同时内存空间中分配了形参空间,接着在方法内对形参空间进行操作。
值传递类型:八种基本数据类型和String
引用传递
public static void main(String[] args) {
MyClass myClass = new MyClass();
change(myClass);
System.out.println(myClass.val);
}
private static void change(MyClass myClass) {
myClass = new MyClass();
myClass.val = 2;
}
public static class MyClass{
int val = 1;
}
运行结果:
1
我们将myClass作为实参传入方法的时候,JVM会新申请出一个空间作为形参空间,此时实参myClass和形参myClass指向同一个空间,这时对形参的指向发生改变,故不会影响实参的值。倘若,change方法中去掉new,那运行结果就必然为2了。
对于JavaScript来说
值传递
function fun(val) {
val++;
console.log("fun:", val);
}
var a = 20;
fun(a);
console.log("外部:", a);
运行结果
将a复制一份传递给val空间,fun函数对val空间进行操作,对形参的改变不会影响到实参
引用传递
function fun(obj) {
obj.val = 99;
console.log("fun:", obj);
}
var a = new Object();
fun(a);
console.log("外部:", a);
运行结果:
恩,a和obj两个空间都指向(引用)一个空间,故,对obj的操作会影响到a
很多人由此认为:这是引用传递,在局部域(形参)修改对象,会影响到实际域(实参)。
但!
请先看这样一个例子
var fun = function (obj) {
obj.val = 99;
obj = {
val : 123,
};
return obj;
}
var object = {
val : 10,
};
var o = fun(object);
console.log("object:", object);
console.log("o:", o);
运行结果:
不是引用传递嘛?为什么外部域没发生改变呢?
程序是这样运行的:
将对象object作为实参传递给形参obj,其实传递的是对象object的首地址
函数将对象首地址复制一份传递给形参后,由函数对形参空间进行操作,在程序中,我们能看出:
函数对形参所指的空间的val进行++操作后改变了obj的指向,现在obj指向一个空间,其val = 123;
所以,在JavaScript来说,引用传递的本质还是值传递,其传递的是对象的地址值!