最近的一个项目,里面各种返回void,参数用引用类型,那叫一个熟和多,但是也把我绕糊涂了。
我就打算好好理一理java的传参机制,整理一番
很多人一听Java的传参,那一定会脱口而出,java都是值传递的。恭喜各位,答对了。
那么,传的是什么值?
如果参数类型是原始类型,那么传过来的就是这个参数的一个副本,也就是这个原始参数的值,这个跟之前所谈的传值是一样的。如果在函数中改变了副本的值不会改变原始的值.
如果参数类型是引用类型,那么传过来的就是这个引用参数的副本,这个副本存放的是参数的地址。如果在函数中没有改变这个副本的地址,而是改变了地址中的 值,那么在函数内的改变会影响到传入的参数。如果在函数中改变了副本的地址,如new一个,那么副本就指向了一个新的地址,此时传入的参数还是指向原来的 地址,所以不会改变参数的值。
这里我给个代码就很好理解了
1 public class ParamterTest {
2 public static void main(String[] args) {
3 List<Integer> list1 = new ArrayList<>();
4 List<Integer> list2 = new ArrayList<>();
5 list1.add(0);
6 list2.add(0); //(1)
7 f(list1, list2);
8 System.out.println("list1 2");
9 p(list1);
10 System.out.println("list2 2");
11 p(list2); //(4)
12 }
13
14 public static void f(List<Integer> list1, List<Integer> list2) {
15 list1.add(1);
16 list2.add(1);
17 list2 = new ArrayList<>(); //(2)
18 list1.add(2);
19 list2.add(2);
20 System.out.println("list1 1");
21 p(list1);
22 System.out.println("list2 1");
23 p(list2); //(3)
24 }
25
26 public static void p(List<Integer> list) {
27 for (Integer i : list) {
28 System.out.println(i);
29 }
30 }
31 }
输出结果
list1 1
0
1
2
list2 1
2
list1 2
0
1
2
list2 2
0
1
要具体解释,就是涉及到堆,栈和方法区了。
(1)list1,list2刚刚成立,都放进了 0,因为是对象的实例所以保存在堆里面。
(2)list1,list2将自己堆的地址传到了方法里,因为是引用所以保存在栈里面,并通过地址往堆里面的实例,放进了 1。但是,此时new了一个实例,list2在栈里面不再指向堆的实例,而是一个新的地址。
(3)list1,list2放进了2,但此处list1依然指向堆的实例,故放进了 2,而list2则是新的地址,堆的list2并没有放进 2。
(4)方法结束,返回的结果使堆的list1,放进了 1 , 2 。list2 因为在方法内中途有新的实例, 只放进了 1 ,而没有 2。
其实一直迷惑我们,是我们判断出错的是String ,明明是一个引用类型,却是基本类型的特性,因为String 实际上是[]char,具体不细说,我就丢个代码,让大家跑跑吧。
public class ParamterStringTest {
public static void main(String[] args) {
String s1 = "a";
String s2 = "a";
f(s1, s2);
System.out.println("s1 2");
p(s1);
System.out.println("s2 2");
p(s2);
}
public static void f(String s1, String s2) {
s1 = "b";
s2 = "b";
System.out.println("s1 1");
p(s1);
System.out.println("s2 1");
p(s2);
}
public static void p(String s) {
System.out.println(s);
}
}
同理,相应的Interge等包装类。