我相信很多刚学Java的小伙伴都很难理解Java到底是值传递还是引用传递的问题,但肯定背过这道面试题。确实,Java就是值传递,那什么原理呢?请往下看。
我们先看一段代码:分析一下这两句打印的结果分别是什么。
public class Test {public static void main(String[] args) {double percent = 10;tripleValue(percent);System.out.println("percent的值为:" + percent);}public static void tripleValue(double x){x = 3 * x;System.out.println("x的值为:" + x);}
}
x的值为:30.0
percent的值为:10.0
可能有小伙伴会问了,我明明将变量percent传到tripleValue方法中了,并在方法内,将值乘以了3,那x和percent的值都应该是30.0啊?
嗯,按逻辑讲确实是这样,但Java却不是这么做的,它在你传参的时候,偷偷的将percent变量拷贝了一个“副本”,也就是x,后面再用3 * x的时候,其实乘以的是副本,早就不是你传的percent变量了,等tripleValue方法结束,参数变量x就被干掉了。
那么肯定又有小伙伴问了,你基本数据类型勉强算你过关,那我传个Java对象总能破你的局了吧,我就不信传一个对象地址,你还没影响?
嗯,还真是有影响,但你还破不了我的局,请看如下代码,假如我想将员工的工资提高三倍(如果这个员工是我就好了):
public class Test {public static void main(String[] args) {Employee e = new Employee(); //创建员工对象e.setSalary(10.0); //设置e员工的工资为10tripleSalary(e);System.out.println("e的工资为:" + e.getSalary());}public static void tripleSalary(Employee x){double addSalary = x.getSalary() * 3; //为员工涨工资x.setSalary(addSalary);System.out.println("x的工资为:" + x.getSalary());}
}
x的工资为:30.0
e的工资为:30.0
从结果上来看,实现方法改变对象参数的状态是完全可以的。理由也很简单,方法得到的是对象引用的“副本”,原来的对象引用和这个副本都引用同一个对象,就类似于这样:
在传参的时候,依然搞了一个副本x,但x和e指向的是同一个对象地址,所以x改了,e也改。
我们再通过一个例子来让你完全理解到底是值传递还是引用传递,下面来编写一个交换两个 Employee 对象的方法:
public static void swap(Employee x, Employee y){Employee temp = x;x = y;y = temp;
}
如果 Java 对对象采用的是按引用调用,那么这个方法就应该能够实现交换:
Employee a = new Employee();
Employee b = new Employee();
System.out.println("a的地址值为:" + a);
System.out.println("b的地址值为:" + b);
swap(a, b);
System.out.println("交换后a的地址值为:" + a);
System.out.println("交换后b的地址值为:" + b);
a的地址值为:com.example.test.controller.Employee@5caf905d
b的地址值为:com.example.test.controller.Employee@27716f4
交换后a的地址值为:com.example.test.controller.Employee@5caf905d
交换后b的地址值为:com.example.test.controller.Employee@27716f4
从结果上看出,a和b并没有实现交换,其实原因很简单,在传递参数的过程中,还是拷贝了两个副本,a的副本是x,b的副本是y,方法中交换的也是x和y交换,压根没a和b什么事,所以可以得出结论,Java是值传递。