![41ce0e434ef6c7a2d721ba24a33a0378.png](https://i-blog.csdnimg.cn/blog_migrate/d7d1f3ee146090693f4f05f08823f065.jpeg)
一、前言
高级语言中函数的参数传递方式只有三种,传值(按值传递),传引用(按引用传递),传地址(按地址传递)。java只有值传递没有引用传递。记住,有的博客中说java引用类型是引用传递,这种说法从语法上严格来说是错误的,有引用和有引用传递是两个概念。
对于高级语言的参数传递一定要从内存模型开始,Java语言中,基本类型(8种)存放在栈内存,引用类型(3种)引用存放在栈内存,实际对象存放在堆内存,由栈内存中的引用指向堆内存中的对象,从而建立关系。
二、代码
2.1 函数参数为基本类型(值传递)
public class ParameterPassingTest {
public static void _swap(int a,int b){
//此种方法 交换两个数 不使用中间变量
a=a+b;
b=a-b;
a=a-b;
System.out.println("_swap a: "+a+",b: "+b);
}
public static void main(String[] args) {
int a=1,b=2;
_swap(a, b);
System.out.println("main a: "+a+",b: "+b);
}
}
输出:
_swap a: 2,b: 1
main a: 1,b: 2
内存分析:
![5489540f5382ed5acd2afd1b4c8cacc3.png](https://i-blog.csdnimg.cn/blog_migrate/081539a8e95de5d3660ea173fa55d4ea.png)
小结:可以看出_swap()方法中a,b两数发生交换,但是main()函数中a,b两数数值没有相应改变。
原因:基本类型存放在栈内存中,函数参数传递方式为值传递。
2.2 函数参数为引用类型(还是值传递)
2.2.1 引用传递??
代码1:
package mypackage;
public class ParameterPassingTest {
int a;
public static void _swap(ParameterPassingTest test1, ParameterPassingTest test2) {
// 此种方法 交换两个数 不使用中间变量
test1.a = test1.a + test2.a;
test2.a = test1.a - test2.a;
test1.a = test1.a - test2.a;
System.out.println("_swap a: " + test1.a + ",b: " + test2.a);
}
public static void main(String[] args) {
ParameterPassingTest test1 = new ParameterPassingTest();
test1.a = 1;
ParameterPassingTest test2 = new ParameterPassingTest();
test2.a = 2;
_swap(test1, test2);
System.out.println("main a: " + test1.a + ",b: " + test2.a);
}
}
输出1:
_swap a: 2,b: 1
main a: 2,b: 1
内存图:
![dbdb5725a0f2afad7db8ba0a3ed28ecf.png](https://i-blog.csdnimg.cn/blog_migrate/163b323efdc46055e72986d6e38f0d3b.png)
![f8fda662f6f964b3c2068fa9f35b1d73.png](https://i-blog.csdnimg.cn/blog_migrate/c227f79416f38631d97a27239e47a01e.png)
小结:乍看之下,引用类型完成了我们所需要的数值交换功能,我们认为它是引用传递,其实不然,请读者继续往下阅读。
2.2.2 引用是另一种形式的值
代码2:
package mypackage;
public class ParameterPassingTest {
int a;
public static void _swap(ParameterPassingTest test1, ParameterPassingTest test2) {
// 此种方法 交换两个数 不使用中间变量
ParameterPassingTest temp = test1;
test1 = test2;
test2 = temp;
System.out.println("_swap test1.a: " + test1.a + ",test2.a: " + test2.a);
}
public static void main(String[] args) {
ParameterPassingTest test1 = new ParameterPassingTest();
test1.a = 1;
ParameterPassingTest test2 = new ParameterPassingTest();
test2.a = 2;
_swap(test1, test2);
System.out.println("main test1.a: " + test1.a + ",test2.a: " + test2.a);
}
}
输出2:
_swap test1.a: 2,test2.a: 1
main test1.a: 1,test2.a: 2
内存图:
![dbdb5725a0f2afad7db8ba0a3ed28ecf.png](https://i-blog.csdnimg.cn/blog_migrate/163b323efdc46055e72986d6e38f0d3b.png)
![64642b9e8faaf513b77ce4f0dec58d30.png](https://i-blog.csdnimg.cn/blog_migrate/e3e7e6707e84f1fb1ff7bbddc648d4b4.png)
小结: 引用类型的引用存放在栈内存中,对象存放在堆内存中,函数参数传递的是引用而不是对象,这里的引用是另一种形式的值,仍为值传递。正是因为是值传递,所有swap()函数中交换引用,主函数中并没有受到影响。
2.2.3 当引用是集合框架的引用时…
代码3:
package mypackage;
import java.util.ArrayList;
import java.util.List;
public class ParameterPassingTest {
public static void main(String[] args) {
List list = new ArrayList();
list.add("a");
list.add("b");
testReferenceParam(list);
System.out.println("main list : " + list);
}
public static void testReferenceParam(List list) {
list.add("c");
list = new ArrayList<>();
list.add("d");
System.out.println("temp list : " + list);
}
}
输出3 :
temp list : [d]
main list : [a, b, c]
内存图:
![287cac48701013e282e6e9e1d6f5219b.png](https://i-blog.csdnimg.cn/blog_migrate/617a3c60be5c6d2e5c1d1b8070ea2b22.jpeg)
小结:再次强调——引用类型的引用存放在栈内存中,对象存放在堆内存中,函数参数传递的是引用而不是对象,引用只是另一种形式的值,所以仍为值传递。这串代码相对于前面更加明显的说明了引用类型的值传递含义,正是因为是值传递,所以当形参list指向一块新的内存区域时,main()函数中的实参的引用所指对象没有受到影响。
三、尾声
无论是基本类型作为参数传递,还是引用作为参数传递,实际上传递的都是值,只是值的的形式不用而已。所以,Java中的参数传递方式只有值传递,完成了。
天天打码,天天进步!!!