理解Java赋值和参数传递机制.docx

 

理解Java赋值和参数传递机制

2009-10-18 19:36

2、前言:
   关于Java的赋值和参数传递是按值(by value)进行的还是按引用(by reference)进行的,这个问题曾经迷惑了很多人,包括我。而且,我想,这个问题还将继续迷惑一些人,包括那些C++的高手。
  
在这里,我不准备用按值(by value)”按引用(by value)”这样的术语来阐述这个问题。因为,从字面的理解来看,这样的术语在不同的人头脑里有不同的含义。我试图从Java数据(包括原始类型(primitive type)和对象(ojbect))在内存中的存储这个角度,用一个自创的术语来阐述我对这个问题的理解。这个术语就是:堆栈区数据复制(Stack Data Copy,简称SDC。详细一点就是:在Java中,不管是赋值操作还是参数传递操作--针对原始类型(primitive type),是对堆栈区的原始类型的值进行复制;针对对象,是对储存在堆栈区的,对象的引用中所储存的对象的值的地址进行复制。 中国网管联盟www_bitscn_com
  
像上面抠字眼的句子读起来比较费力,我在后面将用两个例子并结合一些示意图来阐述我对这个问题的理解。希望各位朋友帮助纠正错误。

3
、正文:
1
)、赋值操作:
例子源码:(Assign.java

  1.  
  2. public class Assign{
  3.    public static void main(String[] args){
  4.      int i = 1;
  5.      Object o = new Object();
  6.      System.out.println("i = " + i + " ; o = " + o ); // Step 1 (示意图:3-1-1
  7.      int j = i;   
  8.      Object p = o;
  9.      System.out.println("i = " + i + " ; j = " + j + " ; o = " + o + " ; p = " + p); //Step 2 (示意图:3-1-2
  10.      j++;
  11.      p = new Object();
  12.      System.out.println("i = " + i + " ; j = " + j + " ; o = " + o + " ; p = " + p); //Step 3 (示意图:3-1-3
  13.    }
  14. }

网管网bitsCN.com

对上面例子的说明:
1),Step 1中,整数i和对象o得到赋值。

示意图3-1-1



从示意图3-1-1中可以看出:整数i存储在堆栈区(Stack);对象o的引用存储在了堆栈区,但是对象o的值却存储在了内存堆中(Heap),对象o的引用存储了对象o的地址。
Step 1
在我的机器上的一次输出结果:

  1.  
  2. i = 1 ; o = java.lang.Object@a90653


至于对象o的值输出来怎么会是那个样子,我只能告诉您:在java程序的一次运行过程中,每个Object对象输出这样的值是唯一的,因此可以借此来判断对象的引用指向的对象是否发生了改变。详情请参考Java API 文档(下同,这里给出的是:J2SE 1.5.0 API 中文版):
[link]http://gceclub.sun.com.cn/Java_Docs/html/zh_CN/api/java/io/PrintStream.html#println(java.lang.Object)[/link]
[link]http://gceclub.sun.com.cn/Java_Docs/html/zh_CN/api/java/lang/Object.html#toString()[/link]
2),Step 2中,把整数i赋值给了整数j,把对象o赋值给了对象p

54ne.com



示意图3-1-2

从示意图3-1-2中可以看出:整数i的值复制给了整数j,整数j同样存储在堆栈区;存储在堆栈区的对象o的引用中存储的对象o的地址C复制给了对象p的引用,对象p的引用同样在堆栈区中。因为对象p的引用得到了对象o的引用复制过来的对象o的值的存储地址C,所以对象p的引用和对象o的引用都指向了在堆(heap)中的同一个对象,并且,这个对象的地址是地址C
Step 2
在我的机器上的一次输出结果:
网管网bitsCN_com

  1.  
  2. i = 1 ; j = 1 ; o = java.lang.Object@a90653 ; p = java.lang.Object@a90653


3),Step 3中,整数j的值加1,赋给了对象p新的对象值。

示意图3-1-3



从示意图3-1-3中可以看出:整数i的值不变,整数j的值加1变为2,整数在堆栈区中;新生成的对象的值存储在了堆(Heap)中,地址为F。新生成对象的地址F存储在了堆栈区p的引用中,替换了原来存储在其中的地址C。于是,p的引用就指向了新生成的对象,这个新生成的对象的地址是地址F。而整数i和对象o?(包括对象o的引用)没有改变也不曾有任何改变(除了初次赋值)。
Step 3
在我的机器上的一次输出结果:

  1.  
  2. i = 1 ; j = 2 ; o = java.lang.Object@a90653 ; p = java.lang.Object@de6ced



至此,通过上面的例子及其示意图和说明,我得到一个结论:

中国网管联盟wwwbitsCNcom


Java赋值操作中,针对原始类型(primitive type),是对堆栈区的原始类型的值进行复制;针对对象,是对储存在堆栈区的,对象的引用中所储存的对象的值的地址进行复制。这就是术语:堆栈区数据复制(Stack Data Copy,简称SDCJava赋值操作中的阐述。

2
)、方法中的参数传递操作:
例子源码:(PassParameter.java

  1.  
  2. public class PassParameter{
  3.    static void showMe(int pi, Object po){
  4.      System.out.println("pi = " + pi + " ; po = " + po); // Step 2 (示意图:3-2-2
  5.      pi++;
  6.      po = new Object();
  7.      System.out.println("pi = " + pi + " ; po = " + po); // Step 3 (示意图:3-2-3
  8.    }
  9.    public static void main(String[] args){
  10.      int i = 1;
  11.      Object o = new Object();
  12.      System.out.println("i = " + i + " ; o = " + o); // Step 1 (示意图:3-1-1
  13.      showMe(i, o);
  14.      System.out.println("i = " + i + " ; o = " + o); // Step 4 (示意图:3-2-3
  15.    }
  16. }

feedom.net

对上面例子的说明:
1),Step 1中,与上面Assign.java中的Step 1相同,略,下面重复其示意图3-1-1

示意图3-1-1



Step 1
在我的机器上的一次输出结果:

  1.  
  2. i = 1 ; o = java.lang.Object@a90653

2),Step 2中,与上面Assign.java中的Step 2类似,只是Assign.java中的整数j和对象p变成了这里的方法showMe()中的参数:整数pi和对象po。并且,由于这里是参数传递,把Assign.java示意图3-1-2中的“=”替换成PassParameter.java示意图3-2-2中的“<--”,以此表示是参数传递。据我的理解,它们是一回事。

示意图3-2-2



Step 2
在我的机器上的一次输出结果:
54ne.com

  1.  
  2. pi = 1 ; po = java.lang.Object@a90653


3),Step 3Step 4合并起来,见示意图3-2-3同样,与上面Assign.java中的Step 3类似。

示意图3-2-3



Step 3
Step 4在我的机器上的一次输出结果:

  1.  
  2. pi = 2 ; po = java.lang.Object@de6ced
  3. i = 1 ; o = java.lang.Object@a90653



至此,通过上面的例子及其示意图和说明,我得到一个结论:
Java方法参数传递操作中,针对原始类型(primitive type),是对堆栈区的原始类型的值进行复制;针对对象,是对储存在堆栈区的,对象的引用中所储存的对象的地址的值进行复制。这就是术语:堆栈区数据复制(Stack Data Copy,简称SDCJava方法参数传递操作中的阐述。

4
,结论
综上所述:在Java中,不管是赋值操作还是方法的参数传递操作--针对原始类型(primitive type),是对堆栈区的原始类型的值进行复制;针对对象,是对储存在堆栈区的,对象的引用中所储存的对象的值的地址进行复制。 中国网管联盟www.bitscn.com
所以,据我的理解,术语:堆栈区数据复制(Stack Data Copy,简称SDC能够有助于理解在Java中进行赋值和传递参数的机制,能够有助于在一定程度上消除传值传引用等语义上的多变性的负面影响,可以提出来供大家交流。

5
,附注:
由于本人水平有限,上面的一切全是基于实践进行的带有一些推测成分在内的个人心得总结。我也以上面的自创术语去成功解释过一些文章中的有关问题(如下面参考资料中的例程)。谨希望在能为部分Java初学者提供一个理解Java赋值和参数传递的手段的同时,更能得到各位朋友的斧正,以便能够对这个问题形成更加正确和准确的认识。在我提高认识的同时,我会在本文原始出处:用"堆栈区数据复制"理解Java赋值和参数传递机制的心得 ([link]http://java.learndiary.com/disDiaryContentAction.do?goalID=2716[/link])中随时更新此文。再次贴出我的邮件:mdx-xx@tom.com。谢谢。

6
,参考资料:

1
),Java参数传递方式 ([link]http://www.jiehoo.com/java-pass-parameter.htm[/link])
2
),破除java神话之二:参数是传址的 ([link]http://www.javaresearch.org/article/showarticle.jsp?column=544&thread=443[/link]) 网管网bitsCN.com
3
),Java 应用程序中的按值传递语义 ([link]http://www.javaresearch.org/article/showarticle.jsp?column=1&thread=706[/link])
4
),我对《Java 应用程序中的按值传递语义》的理解 ([link]http://www.javaresearch.org/article/showarticle.jsp?column=1&thread=3156[/link])
5
),Thinking in Java, 3rd Edition in Java ([download]http://www.mindviewinc.com/downloads/TIJ-3rd-edition4.0.zip[/download])

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值