java 所谓的值传递和引用传递

来源:互联网 发布:开淘宝网店发货图片 编辑:程序博客网 时间:2024/06/05 17:44


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


先从最开始谈吧



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

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

以下是值传递


以下是地址传递



以下为地址传递

eg:

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

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


引用传递demo

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

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中方法参数的传递,对象是传递引用的拷贝,基本类型是传递值


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

本人总结的不好,大家可以看一看这位大神的,还有这个   http://blog.csdn.net/faintbear/article/details/198021

http://blog.sina.com.cn/s/blog_59ca2c2a0100qhjx.html#cmt_2041332

点击打开链接







0 0
原创粉丝点击