首先先说结论:C语言中参数传递有值传递,地址传递,引用传递。但java中的参数传递只有值传递
#include<stdio.h> void test(int a) {printf("a的值:%d ,",a);printf("a的地址:%d\n",&a); }int main() {int a =10;printf("a的值:%d ,",a);printf("a的地址:%d\n",&a); test(a);return0; }
执行这段代码,我们发现运行结果是这样的:
清晰的看到通过值传递后函数中的a与实参a在内存中地址不同,所以在函数中对a进行修改是影响不到实际的a的。
#include<stdio.h>int main() {int a =10;int* b = &a;printf("a的值:%d\n",a);printf("a的地址:%d\n",&a);printf("b的值:%d\n",b);printf("b的地址:%d\n",&b);return0; }
跑出来的结果
但是我这里用 int* b是为了说明:指针其实是一种特殊的数据类型,所以:
int* b其实就是声明b是一个指针变量
上面的代码中把a的地址赋值给b(指针变量),而这个指针变量有存放在内存中的某个地方
#include<stdio.h> void test(int* b) {int c =20;*b = c; }int main() {int a =10;int* b = &a;printf("处理前:a的值:%d\n",a);printf("处理前:a的地址:%d\n",&a);printf("处理前:b的值:%d\n",b);printf("处理前:b的地址:%d\n",&b); test(b);//test(&a);printf("处理后:a的值:%d\n",a);printf("处理后:a的地址:%d\n",&a);printf("处理后:b的值:%d\n",b);printf("处理后:b的地址:%d\n",&b);return0; }
很多人分不清地址传递与引用传递,甚至认为两者是相同的,但二者的根本区别就在于,是否开辟了一段新的内存来存放地址
#include<stdio.h>int main() {int a =10;int& b = a;printf("a的值:%d\n",a);printf("a的地址:%d\n",&a);printf("b的值:%d\n",b);printf("b的地址:%d\n",&b);return0; }
下面是运行结果:
我们可以看到a和b的值和地址都是相同的,所以调用b,就是调用a,对b赋值就是对a赋值。
#include<stdio.h> void test(int& b) {int c =20; b = c; }int main() {int a =10;int& b = a;printf("处理前:a的值:%d\n",a);printf("处理前:b的值:%d\n",b); test(b);//test(a);printf("处理后:a的值:%d\n",a);printf("处理后:b的值:%d\n",b);return0; }
三种传参方式比较:(以交换数据为例)
#include<stdio.h> void swap(int a,int b) {int temp = a; a = b; b = temp; } void swap2(int& a,int& b) {int temp = a; a = b; b = temp; } void swap3(int* a,int* b) {int temp =*a;*a =*b;*b = temp; }int main() {int a =10;int b =20;printf("交换前a =%d, b =%d\n",a,b); swap(a,b);//swap2(a,b);//swap3(&a,&b);printf("交换后a =%d, b =%d\n",a,b);return0; }
值传递:失败
地址传递:成功
引用传递:成功
但是又有不少文章抨击上面文章的这种观点,并且表明:java中只有一种参数传递方式:值传递
以这篇文章为代表:Java:传值还是传引用?
因为java中不存在指针的概念,所以我们想像在C语言中那样为交换数据封装一个方法是无法实现的,因为java中并不存在指针类型(既有优点也有缺点)
publicclass paraTest01 {publicstaticvoidmain(String[] args) {int a =10;int b =20; swap(a,b); System.out.println("最终 a = " + a); System.out.println("最终 b = " + b); }publicstaticvoidswap(int a,int b){int temp = a; a = b; b = temp; System.out.println("方法中:a = " + a); System.out.println("方法中:b= " + b); } }
运行结果:
这个不需要解释了,应该都懂
之前的第一种观点认为:引用数据类型在进行参数传递的时候是引用传递,接下来我们依次探究
publicclass ArrayParaTest {publicstaticvoidmain(String[] args) {int[] array = {1,2,3,4,5}; change(array); System.out.println(array[0]); }publicstaticvoidchange(int[] array){ array[0] =0; } }
结果是数组中的第一个元素被替换了。看到这可能很多人就认为这里就是引用传递,别急,我们继续看
publicclass paraTest02 {publicstaticvoidmain(String[] args) {int[] array = {1,2,3,4,5}; change(array);for (int temp : array){ System.out.print(temp +" "); } }publicstaticvoidchange(int[] array){ array =newint[]{6,7,8,9,0}; } }
懵逼了吗?说好的引用传递呢?很多人觉得,只要是一种类型的参数传递,要么就是能改变实际参数,要么就是不能改变实际参数。这怎么既有改变又有没改变呢?
publicclass ClassPara {publicstaticvoidmain(String[] args) { Person p =new Person("张三"); change(p); System.out.println(p.getName()); }publicstaticvoidchange(Person p){ p =new Person("李四"); } } class Person{private String name;publicPerson(String name) {this.name = name; }publicvoidsetName(String name) {this.name = name; }public StringgetName() {return name; } }
原对象中的属性没有发生变化,但如果是下面的例子
publicclass ClassPara {publicstaticvoidmain(String[] args) { Person p =new Person("张三"); change(p); System.out.println(p.getName()); }publicstaticvoidchange(Person p){ p.setName("李四"); } } class Person{private String name;publicPerson(String name) {this.name = name; }publicvoidsetName(String name) {this.name = name; }public StringgetName() {return name; } }
这次的运行结果就是这样的:
其实就是对String类的任何修改 就是新创建了一个对象,并把新的对象的引用赋给之前的对象的引用。
所以下面这个例子也就可以理解了
publicclass StringParaTest {publicstaticvoidmain(String[] args) { String str ="AAA"; change(str); System.out.println(str); }publicstaticvoidchange(String str){ str ="abc";//等价于:// char data = {'a'.'b','c'};//str = new String(data); } }
运行结果我们可以猜出来:
实质上在方法内还是只改变了对象的引用,所以没有什么卵用。