夢想飛翔

          自強不息
          posts - 111, comments - 30, trackbacks - 0, articles - 0
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          ?

          提綱:
          1、版權聲明
          2、前言
          3、正文
          4、結論
          5、附注
          6、參考資料

          =======================================================

          1、版權聲明:
          ??本文作者:little,原始出處:用"堆棧區數據復制"理解Java賦值和參數傳遞機制的心得?([link]http://java.learndiary.com/disDiaryContentAction.do?goalID=2716[/link]),郵件:mdx-xx@tom.com。如有任何反饋意見請聯系作者,作者會在本文原始出處隨時更新此文。轉載及引用請保留此版權聲明,謝謝。

          2、前言:
          ??關于Java的賦值和參數傳遞是按值(by?value)進行的還是按引用(by?reference)進行的,這個問題曾經迷惑了很多人,包括我。而且,我想,這個問題還將繼續迷惑一些人,包括那些C++的高手。
          ??在這里,我不準備用“按值(by?value)”和“按引用(by?value)”這樣的術語來闡述這個問題。因為,從字面的理解來看,這樣的術語在不同的人頭腦里有不同的含義。我試圖從Java數據(包括原始類型(primitive?type)和對象(ojbect))在內存中的存儲這個角度,用一個自創的“術語”來闡述我對這個問題的理解。這個術語就是:“堆棧區數據復制(Stack?Data?Copy,簡稱SDC)”。詳細一點就是:在Java中,不管是賦值操作還是參數傳遞操作--針對原始類型(primitive?type),是對堆棧區的原始類型的值進行復制;針對對象,是對儲存在堆棧區的,對象的引用中所儲存的對象的值的地址進行復制。
          ??像上面摳字眼的句子讀起來比較費力,我在后面將用兩個例子并結合一些示意圖來闡述我對這個問題的理解。希望各位朋友幫助糾正錯誤。

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

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


          對上面例子的說明:
          (1),Step?1中,整數i和對象o得到賦值。

          示意圖3-1-1

          ?
          chart3-1-1.bmp
          從示意圖3-1-1中可以看出:整數i存儲在堆棧區(Stack);對象o的引用存儲在了堆棧區,但是對象o的值卻存儲在了內存堆中(Heap),對象o的引用存儲了對象o的地址。
          Step?1在我的機器上的一次輸出結果:
          1. 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。

          示意圖3-1-2

          chart3-1-2.bmp

          從示意圖3-1-2中可以看出:整數i的值復制給了整數j,整數j同樣存儲在堆棧區;存儲在堆棧區的對象o的引用中存儲的對象o的地址C復制給了對象p的引用,對象p的引用同樣在堆棧區中。因為對象p的引用得到了對象o的引用復制過來的對象o的值的存儲地址C,所以對象p的引用和對象o的引用都指向了在堆(heap)中的同一個對象,并且,這個對象的地址是地址C。
          Step?2在我的機器上的一次輸出結果:
          1. i?=?1?;?j?=?1?;?o?=?java.lang.Object@a90653?;?p?=?java.lang.Object@a90653

          (3),Step?3中,整數j的值加1,賦給了對象p新的對象值。

          示意圖3-1-3

          chart3-1-3.bmp

          從示意圖3-1-3中可以看出:整數i的值不變,整數j的值加1變為2,整數在堆棧區中;新生成的對象的值存儲在了堆(Heap)中,地址為F。新生成對象的地址F存儲在了堆棧區p的引用中,替換了原來存儲在其中的地址C。于是,p的引用就指向了新生成的對象,這個新生成的對象的地址是地址F。而整數i和對象o的?(包括對象o的引用)沒有改變也不曾有任何改變(除了初次賦值)。
          Step?3在我的機器上的一次輸出結果:
          1. i?=?1?;?j?=?2?;?o?=?java.lang.Object@a90653?;?p?=?java.lang.Object@de6ced


          至此,通過上面的例子及其示意圖和說明,我得到一個結論:
          在Java賦值操作中,針對原始類型(primitive?type),是對堆棧區的原始類型的值進行復制;針對對象,是對儲存在堆棧區的,對象的引用中所儲存的對象的值的地址進行復制。這就是術語:“堆棧區數據復制(Stack?Data?Copy,簡稱SDC)”在Java賦值操作中的闡述。

          2)、方法中的參數傳遞操作:
          例子源碼:(PassParameter.java)
          1. public?class?PassParameter{
          2. ??static?void?showMe(int?pi,?Object?po){
          3. ????System.out.println("pi?=?"?+?pi?+?"?;?po?=?"?+?po);?//?Step?2?(示意圖:3-2-2)
          4. ????pi++;
          5. ????po?=?new?Object();
          6. ????System.out.println("pi?=?"?+?pi?+?"?;?po?=?"?+?po);?//?Step?3?(示意圖:3-2-3)
          7. ??}
          8. ??public?static?void?main(String[]?args){
          9. ????int?i?=?1;
          10. ????Object?o?=?new?Object();
          11. ????System.out.println("i?=?"?+?i?+?"?;?o?=?"?+?o);?//?Step?1?(示意圖:3-1-1)
          12. ????showMe(i,?o);
          13. ????System.out.println("i?=?"?+?i?+?"?;?o?=?"?+?o);?//?Step?4?(示意圖:3-2-3)
          14. ??}
          15. }


          對上面例子的說明:
          (1),Step?1中,與上面Assign.java中的Step?1相同,略,下面重復其示意圖3-1-1。

          示意圖3-1-1

          chart3-1-1.bmp
          ?

          Step?1在我的機器上的一次輸出結果:
          1. 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

          chart3-2-2.bmp

          Step?2在我的機器上的一次輸出結果:
          1. pi?=?1?;?po?=?java.lang.Object@a90653

          (3),Step?3和Step?4合并起來,見示意圖3-2-3同樣,與上面Assign.java中的Step?3類似。

          示意圖3-2-3

          ?chart3-2-3.bmp

          Step?3和Step?4在我的機器上的一次輸出結果:
          1. pi?=?2?;?po?=?java.lang.Object@de6ced
          2. i?=?1?;?o?=?java.lang.Object@a90653


          至此,通過上面的例子及其示意圖和說明,我得到一個結論:
          在Java方法參數傳遞操作中,針對原始類型(primitive?type),是對堆棧區的原始類型的值進行復制;針對對象,是對儲存在堆棧區的,對象的引用中所儲存的對象的地址的值進行復制。這就是術語:“堆棧區數據復制(Stack?Data?Copy,簡稱SDC)”在Java方法參數傳遞操作中的闡述。

          4,結論
          綜上所述:在Java中,不管是賦值操作還是方法的參數傳遞操作--針對原始類型(primitive?type),是對堆棧區的原始類型的值進行復制;針對對象,是對儲存在堆棧區的,對象的引用中所儲存的對象的值的地址進行復制。
          所以,據我的理解,術語:“堆棧區數據復制(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])
          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])

          ??????????????????????????????????????????????????????????????全文完
          ??????????????????????????????????????????????????????????????2006年11月22日午????
          主站蜘蛛池模板: 自治县| 海口市| 凉山| 湘潭县| 普兰店市| 浑源县| 灵武市| 库尔勒市| 信丰县| 铜梁县| 尼勒克县| 安乡县| 滦平县| 建湖县| 陵川县| 鹿泉市| 昌图县| 封丘县| 重庆市| 河南省| 邹城市| 平顶山市| 福清市| 海城市| 平谷区| 那曲县| 荥经县| 东阿县| 恭城| 通江县| 忻州市| 万源市| 四平市| 梁平县| 新绛县| 梧州市| 凉城县| 彭阳县| 平度市| 赤水市| 洪江市|