Java的值传递问题
首先我们应该明确Java中是只存在值传递的。那么,值传递是什么呢?
值传递:指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
现在我们通过分析两种数据类型来看看Java中的值传递过程。
(1)基本数据类型
public class FirstTest { public void changeA(int a) { a = 2; } public static void main(String args[]) { FirstTest ft = new FirstTest(); int a = 5; ft.changeA(a); System.out.println(a); // a = 5 } }
我们可以看到这个简单的例子中先把在main函数里定义了一个a = 5,然后我们想通过changeA函数来改变a的值,救过输出一看发现并没有更改成功,那么这是怎么一回事呢?
通过值传递的定义我们可以知道当a作为实际参数在函数中传值时,会复制一份a2(便于区分这么叫,其实就是changeA函数中的形参a),那么这个时候a和a2都为5,但其实他们两是两个独立的变量,那我修改a2的值为2对a就不造成影响,所以最后a仍然等于5。.
(2)引用数据类型
情况一:
class Second{ public int a; } public class FirstTest { public void changeA(Second sd) { sd.a = 2; } public static void main(String args[]) { FirstTest ft = new FirstTest(); Second sd = new Second(); sd.a = 5; ft.changeA(sd); System.out.println(sd.a); // a = 2 } }
这里可以看到我们创建了一个新类Second,里面定义了一个变量a,现在我们还是想通过changeA函数来改变这个a,只不过这次我们想通过传引用数据的方式来实现。
这里我们最好了解一下Java的内存机制(可以戳这个视频,个人认为讲的非常到位),不过不了解也不要紧,大家应该都知道当new一个对象的时候会在堆中开辟一块空间,此时sd这个对象里其实存储的是这块内存空间的地址(也就是说sd指向这块内存空间),那么根据值传递的定义,当我们将sd传入changeA函数时,会复制一份sd2(实际上是changeA的形参sd),但是由于sd其实是等于一个地址,那么sd2也应该等于同样的地址,也就是说sd2页指向了那块内存空间,这时候你通过sd2去改变a也就相当于通过sd去改变a,所以a改变了。
情况二:
class Second{ public int a; } public class FirstTest { public void changeA(Second sd) { sd = new Second(); //(1) sd.a = 2; // (2) } public static void main(String args[]) { FirstTest ft = new FirstTest(); Second sd = new Second(); sd.a = 5; ft.changeA(sd); System.out.println(sd.a); // a = 5 } }
这里我将changeA函数做了小小的变化,最终的结果就又改变了。前面的过程还是和之前一样的,但是在changeA函数中,由于 (1)中new又在堆中开辟了一块内存空间,再将这块空间的地址赋给了sd2,那么此时sd2就不指向原来的那块内存空间了(可以说这是sd2完全是一个新的对象),那么改变sd2的a就不会引起sd的a改变。