最近翻车了,之前学习了java参数传递机制以为理解了,但是突然发现还是理解的不太深刻,果然有些问题除非亲身经历否则难以彻底理解。
之前一般都是利用集合来作为方法的入参,然后再方法内部,操作集合,方法调用之后发现集合也的确发生了自己希望的改变,这一次,也是集合参数作为方法入参,在方法内部将入参重新赋值,以为方法执行完成后,集合会发生改变,没想到却失败了。大致意思如下:
private void test1() {
// 这里的入参list是栈中临时生成的引用变量 和 外层list同时指向了内存同一块数据
// 这里赋值只是将这个临时变量指向了Arrays.asList(1) 而外层list并没有改变
// 方法不能让对象参数引用一个新的对象,方法得到的永远都是拷贝值
List<Integer> list = new ArrayList<>();
System.out.println("before = " + list);
change(list);
System.out.println("outer after = " + list);
}
private void change(List<Integer> list) {
list = Arrays.asList(1);
System.out.println("inner after = " + list);
}
在外层定义一个空集合,传入到change方法中,在change方法中改变入参,以为方法执行完成list集合会改变,没想到结果如下:方法内部的确改变了 但是外部集合没有改变。
before = []
inner after = [1]
outer after = []
这是为啥?说到底还是对于java方法入参传参机制不太了解,一句话,java入参传参都是拷贝赋值传递,如果入参是基本类型 则拷贝新的值传递,如果入参是引用 则拷贝引用对象赋值传递。换句话说,方法内部使用的参数list和外部定义的list不是同一个变量,change方法内部参数list是方法执行时在栈中临时生成的,方法执行完成后会自动销毁。
左边为栈 右边为堆,由下到上执行test1 定义list指向空集合,继而执行change方法,方法入参list此时生成临时变量list(标红),初始时也指向了空集合,后面赋值为集合1 打印输出 方法change结束 list(标红)销毁,注意该过程中list一直指向空 没有变化。
方法不能让对象参数引用一个新的对象,方法得到的永远都是拷贝值
再看下一个
private void test2() {
// 这里的入参list是栈中临时生成的引用变量 和 外层list同时指向了内存同一块数据
// 这里list指向的内存区域增加数据 由于外层list指向同一块区域 因此list数据会改变
// 方法可以改变对象参数的状态,因为方法可以通过对象引用的拷贝修改对象状态
List<Integer> list = new ArrayList<>();
System.out.println("before = " + list);
change2(list);
System.out.println("inner after = " + list);
}
private void change2(List<Integer> list) {
list.add(1);
System.out.println("inner after = " + list);
}
运行结果如下:
before = []
inner after = [1]
inner after = [1]
可知传入的list对象改变了,这又是为啥,
test2中的list和change2中list指向了内存中同一个内存区域,改变标红list中添加1 此时list也会改变
方法可以改变对象参数的状态,因为方法可以通过对象引用的拷贝修改对象状态
再看下一个
private void test3() {
int a = 1;
Integer b = Integer.valueOf(1);
System.out.println("before a = " + a);
System.out.println("before b = " + b);
change3(a, b);
System.out.println("outer after a = " + a);
System.out.println("outer after b = " + b);
}
private void change3(int a, Integer b) {
// 这里的 a b都是方法执行时内存栈中生成的临时变量 当方法执行完成后自动销毁
// 方法不能修改基本数据类型的参数,他们改变的仅仅是他们的拷贝
a = 2;
b = Integer.valueOf(2);
System.out.println("inner after a = " + a);
System.out.println("inner after b = " + b);
}
结果如下:
before a = 1
before b = 1
inner after a = 2
inner after b = 2
outer after a = 1
outer after b = 1
可知对于基本类型 方法内部如何变化都不能改变外部实际参数的值。
方法不能修改基本数据类型的参数,他们改变的仅仅是他们的拷贝
方法入参传递都是值拷贝赋值传递,方法内部参数都是方法执行时栈中临时生成的变量,当如果是基本类型时 则必定不会影响外部实际参数;当如果是引用类型时,栈中临时生成的变量和外部实际参数执行同一个内存区域,如果方法内存改变内存区域 则外部参数执行的内容也会随之改变,如果是重新赋值 则不会改变。
为了便于理解test1 将change方法入参改一下
private void test1() {
// 这里的入参list是栈中临时生成的引用变量 和 外层list同时指向了内存同一块数据
// 这里赋值只是将这个临时变量指向了Arrays.asList(1) 而外层list并没有改变
// 方法不能让对象参数引用一个新的对象,方法得到的永远都是拷贝值
List<Integer> list = new ArrayList<>();
System.out.println("before = " + list);
change(list);
System.out.println("outer after = " + list);
}
private void change(List<Integer> list2) {
list2 = Arrays.asList(1);
System.out.println("inner after = " + list2);
}