最近学校课程java上了一半,我发现我一直都不太懂值传递,引用传递什么的,这次一定要弄懂

先从最开始谈吧

一、什么叫做值传递与引用传递

实参与形参
    - 存储单元(左值)
    - 存储内容(右值)
根据所传递的实参的“内容”,参数传递可分为:
    - 传值调用:传递实参的右值到形参单元;
    - 引用调用:传递实参的左值到形参单元;
    - 值-结果调用:传递实参的右值;在控制返回时将右值写回到实参相应左值单元(如果有的话);
    - 换名调用:传递实参的“正文”。

以下是值传递



以下是地址传递





以下为地址传递

eg:

1. void Exchg2(int *px, int
2. {  
3. int
4.       *px = *py;  
5.       *py = tmp;  
6. "*px = %d, *py = %d.\n",*px, *py);  
7. }  
8. main()  
9. {  
10. int
11.       Exchg2(&a, &b);  
12. "a = %d, b = %d.\n", a,b);  
13. return(0);  
14. }

在调用Exchg2(&a,&b)时最开始做的两个隐含动作是:int *px=&a;int *py=&b;.及 px=&a;py=&b;.




引用传递demo

1. void Exchg3(int &x, int
2. {  
3. int
4.      x = y;  
5.      y = tmp;  
6. "x= %d,y = %d\n", x, y);  
7. }  
8. main()  
9. {  
10. int
11.      Exchg3(a, b);  
12. "a= %d, b = %d\n", a, b);  
13. return(0);  
14. }

Exchg3函数的定义处Exchg3(int&x, int &y)。调用时我们可以像值传递(如: Exchg1(a, b); )一样调用函数(如: Exchg3(a,b);)。但是x、y前都有一个取地址符号“&”。有了这个,调用Exchg3时函数会将a、b 分别代替了x、y了,我们称:xy分别引用了ab变量。这样函数里操作的其实就是实参a、b本身了,因此函数的值可在函数里被修改


这个道理大家都懂,那么在java中是如何运作的呢?

二、java专场

句柄概念

java并没有c++中指针、地址的概念,它只有句柄(handler)的概念。还以凤舞凰扬的两个方法为例:

public void call(Test t) { 
 Test t2 = new Test(); 
 t2.setName("cba'); 
 t.setName("abc"); 
 t = t2 ; 
 } 

 public static void main(String[] arg) { 
 Test obj = new Test(); 
 call (obj) ; 
 System.out.println("obj"+obj.getName()); 
 }



总共构建了两个Test对象,假设称main方法构建的对象为“对象1”,call方法构建的对象为“对象2”,
在main方法中,变量obj获得了“对象1”的句柄,
在参数传递中,变量obj把这个句柄传递给变量t,
在call方法中,变量t首先改变了“对象1”的属性,然后变量t又获得了“对象2”的句柄(但obj仍然是“对象1”的句柄),
call方法返回后,由于“对象2”失去了唯一的句柄,不可避免的进入垃圾收集器的视线。而obj仍然是“对象1”的句柄,由于“对象1”的属性已经被重新设置,所以我们可以看到打印出来的结果是“abc”。

我更喜欢下面这个例子

一个句柄的传递会使调用者的对象发生意外的改变。

public class Testit { 
 private String name; 

 public String getName() { 
 return name; 
 } 

 public void setName(String name) { 
 this.name = name; 
 } 

 public static void main(String[] args) { 
 Testit a = new Testit(); 
 a.setName("a"); 
 Testit b = new Testit(); 
 b.setName("b"); 
 System.out.println("before swap: " + "a=" + a + " name: " + a.getName()); 
 swap(a,b); 
 System.out.println("after swap: " + "a=" + a + " name: " + a.getName()); 
 } 

 private static void swap(Testit swap1, Testit swap2) { System.out.println(" swaping: " + "a=" + a + " name: " + a.getName()); 
STestit temp; 
 temp = swap1; 
 swap1 = swap2; 
 swap2 = temp; 
 swap1.setName("a's name"); 
 swap2.setName("b's name"); 
 } 

 }

输出结果:


before swap: a=com.lib.Testit@16930e2 name: a 
swaping: a= com.lib.Testit@16930e2 name: a 
after swap: a=com.lib.Testit@16930e2 name: b's name

我们看到,a依旧是原来那个a,但name却不是原来那个name了!
在swap()方法中,swap1和swap2互相换过来了,这个时候swap2指向的是a,所以在setName()的时候改变的是a的name,而不是b的name。

为什么会这样呢?
Java里的传值实际上是拷贝引用,而不是拷贝对象。

浏览了很多博主的总结我看到下面几句话

1、java只有值传递方式

2、在Java中方法参数的传递,对象是传递引用,基本数据类型是传递值()

3、java传递是引用的拷贝,既不是引用本身,更不是对象

总的来说,我接受这样的说法:在java中方法参数的传递,对象是传递引用的拷贝,基本类型是传递值

如有错误,希望指证,谢谢