方法(函数)的参数传递方式一共有两种,分别是值传递和引用传递:
- 值传递:
方法调用时,实际参数把它的值传递给对应的形式参数,函数接收的是原始值的一个copy,此时内存中存在两个相等的基本类型,即实际参数和形式参数,后面方法中的操作都是对形参这个值的修改,不影响实际参数的值。
2引用传递:
也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,函数接收的是原始值的内存地址;在方法执行中,形参和实参内容相同,指向同一块内存地址,方法执行中对引用的操作将会影响到实际对象。
在Java中只有值传递,没有引用传递。比如下面的例子:
public static void add(int i){
i = 2;
}
在main方法中调用:
int i = 1 ;
add(i);
System.out.println("i = " + i);
控制台输出:
结果是并没有改变,所以显而易见,调用add这个方法,传入的是i的copy,在add中对i进行任何操作都不会影响原本的值。
那么可能会有人问,为什么下面的例子就改变了原本的值呢?
Man类:
public class Man {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
修改名字的方法:
public static void updName(Man man ){
man.setName("小鹏");
}
在main方法中调用:
Man man = new Man();
man.setName("小明");
System.out.println("调用函数之前的名字:" + man.getName());
updName(man);
System.out.println("调用函数之后的名字:" + man.getName());
控制台输出:
调用函数之前的名字是小明,调用之后就变成了小鹏,这不是改变了原来的值了吗?
其实这里是陷入了一个思想误区,想弄清楚这个问题,首先要明白对象是什么?
简单来说,对象就是对一块内存区域的引用,而这块内存区域其实就是对象真正的值。
在通过Man man = new Man()创建对象的时候JVM都做了哪些操作?
简单来说对象在被创建的时候,编译器会在栈中为Man man 划分一块区域,然后会在堆中为对象的主体划分一块内存区域,并将该内存地址的引用返回给man。这样就可以通过man中存储的地址引用找到该对象真正的内存区域。
(之前写过一个介绍对象的帖子,有兴趣可以看看 传送门)
明白了这个原理之后,就可以将上面的例子形象化一下:
对象指向的内存区域相当于一个密码箱,而对象本身man就是这个箱子的钥匙。在执行updName(man)方法的时候,其实就相当于你复制了一把钥匙,用来打开这个密码箱。因为打开的是同一个箱子,所以这个时候你把箱子里面的水杯替换成笔记本之后,用原配的钥匙(man)再打开箱子的时候,里面的东西一定变成了笔记本,因为你改变的是内存区域里存储的内容,而不是钥匙。
那么相对应的,如果你在复制而来的钥匙上刻下你的名字,会影响原配钥匙(man)吗?当然不会,因为这是两个不同的钥匙!
比如下面这个例子:
方法:
/**
* 对象重赋值
* */
public static void updObj(Man man){
System.out.println("方法中重赋值前的名字:" + man.getName());
System.out.println("方法中重赋值前的对象地址:" + man.toString());
man = new Man();
System.out.println("重新赋值后的名字:" + man.getName());
System.out.println("重新赋值后的对象地址:" + man.toString());
}
方法调用:
man.setName("小明");
System.out.println("调用方法之前的名字:" + man.getName());
System.out.println("调用方法之前的对象地址:" + man.toString());
updObj(man);
System.out.println("调用方法之后的名字:" + man.getName());
System.out.println("调用方法之后的对象地址:" + man.toString());
控制台打印结果:
这里就能很明显的看出来,重赋值之后,对象指向的内存区域发生了改变(也就是换了一个箱子),不管你在方法中怎么对重赋值后的对象操作,对原本对象以及对象中的内容是没有任何改变的(往新箱子里放东西不会影响旧箱子)。
也就是说方法中操作的其实是该对象的copy,并不是其本身。这就验证了Java中是没有引用传递的,只有值传递。
如果我写的不够简单明了,请留评,我及时修改。