java中的值传递
我们都知道,在java中,简单的swap交换两个对象是行不通的,对于基本数据类型这很好理解,因为方法上的参数是值的复制,就是很好理解的那种值传递。但是如果是交换两个对象该如何理解呢?
@Data
public class Number {
private Integer num;
public Number(Integer n) {
this.num = n;
}
}
public static void main(String[] args) {
Number n1 = new Number(1);
System.out.println(n1);
changeNum(n1);
System.out.println(n1);
setNum(n1);
System.out.println(n1);
}
public static void setNum(Number number) {
number.setNum(999);
}
public static void changeNum(Number number) {
number = new Number(111);
}
在探究问题之前,先来了解概念:
值传递: 值传递指的是在函数调用的时候将参数复制一份,这样在函数中的操作就对实际的参数没有影响;
引用传递:引用传递是将参数的地址传入函数操作,这样在函数操作的时候就会改变实际参数;
所以值传递较引用传递的区别是:
值传递会创建一个副本(复制一份),而引用传递不会创建副本;
接下来注意,由于上述的区别,造成的两者的不同是:
创建了副本的不会对原副本造成影响,而没有创建副本的会对元数据有影响;
那么我们区分值传递还是引用传递的根本是看它到底有没有复制副本;而会不会对实际参数造成影响是有没有创建副本带来的后果;
接下来看上面的代码:
为什么setNum()
可以改变对象的值,而changeNum()
却不行呢?因为java并不是简单的把对象复制了一份传入函数,而是将对象的引用
复制了一份传入函数。也就是说在函数调用的时候,实际对象还是只有一个,但是它有2个引用,一个是本身的引用,另一个是调用函数的时候引用的复制,这2个引用都指向这个对象。所以就造成了上述情况。
setNum()
的内部实际操作是改变属性,引用是没有属性的,要改变的是引用指向的对象的属性,他们指向的是同一个对象,那这个操作就会修改实际对象。
changeNum()
就不一样了,它做的是改变引用的指向,但是这个引用并不是原来实际对象的引用,而是一个复制的引用,复制的引用出了函数就不存在了,所以不会对实际对象有所改变;
最后在回到开始的问题: 为什么java是值传递?这里答案已经很明显了,java对参数的处理是复制了一份实际参数的引用,而值传递的特点就是会复制一个副本,所以这就是值传递,只不过有点特殊(没有直接复制参数);也许你还会说: 它传递的就是一个引用啊,只不过是复制过的引用,也是引用啊,这是引用传递。这里就突出了一个概念的重要性,不是说传递的是引用就是引用传递,而是看概念,既然它创建了一个副本,这就不符合引用传递的概念,所以从概念上说,这时值传递。不过要是抛开概念,要说是引用传递也没有什么问题,但是概念不就是让人不那么混淆而存在的嘛,既然已经有了定义,遵守它就好了。