最近学校课程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了,我们称:x、y分别引用了a、b变量。这样函数里操作的其实就是实参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中方法参数的传递,对象是传递引用的拷贝,基本类型是传递值
如有错误,希望指证,谢谢