java世界
          有些人注定要生活在彼岸,可以親近可以愛憐,甚至可以窮盡一生去思念,只是無法觸及有些距離,注定不能跨越只能倆倆相望,就像有些愛只能養在心里長在眼中,不能捧在手里放在身邊,注定只能邂逅無法遭遇!
          posts - 12,comments - 15,trackbacks - 0

          傳值?還是傳引用?

          (Wang hailong)

           

          關于編程的參數傳遞問題,總是存在著這樣的爭論。傳值?還是傳引用?(還是傳指針?還是傳地址?)這些提法,經常出現在C++, java, C#的編程技術文檔里面。這個問題也經常引起開發人員的爭論,徒耗人力物力。實際上,這根本不成為問題,只是由于人為加入的概念,混淆了人們的視聽。

          從程序運行的角度來看,參數傳遞,只有傳值,從不傳遞其它的東西。只不過,值的內容有可能是數據,也有可能是一個內存地址

          開發人員應該了解程序的編譯結果是怎樣在計算機中運行的。程序運行的時候,使用的空間可以分為兩個部分,棧和堆。棧是指運行棧,局部變量,參數,都分配在棧上。程序運行的時候,新生成的對象,都分配在堆里,堆里分配的對象,棧里的數據參數,或局部變量。

          下面舉一個C++的例子。

          public class Object{

            int i;

            public Object(int i){

                 this.i = i;

            }

           

                 public int getValue(){

                        return i;

                 }

           

                 public void setValue(int i){

                        this.i = i;

                 }

          };

           

          class A {

                 Void func1(int a, Object b){

                        Object * c = new Object( a );

                       

          b = c;

                 }

           

          public      void main(){

                 Object * param = new Object( 1 );

           

                        func1( 2,  param )

                       

                        // what is value of parram now ?

                        // it is still 1.

              }

          };

           

          我們來看一下,當調用到func1函數時,運行到Object * c = new Object( a ); 棧和堆的狀態。不同編譯器生成的代碼運行的結果可能會稍有不同。但參數和局部變量的大致排放順序都是相同的。

           

          這時候,我們來看,param變量被壓入運行棧的時候,只是進行了簡單的復制。把param里面的內容拷貝到b里面。這時候,b就指向了Object(1)。這里的參數傳遞,是把param的值傳遞給b

          下面我們來看,程序執行到b = c;時候的堆棧狀態。

           

          我們可以看到,b現在指向了Object(2)。但是對param的值毫無影響。param的值還是Object(1)

          所以,我們說,對參數的賦值不會影響到外層函數的數據,但是,調用參數的操作方法,卻等于直接操作外層函數的數據。比如,如果我們在func1()函數中,不調用b=c;而調用b.setValue(3),那么Object(1)的數據就會變為3param的數據也會改變為3

          javaC#中的情況,也都是一樣。

          C++還有一種變量定義方法,表面上看起來,不符合上面的說明,這里進行說明。

          Object * a = new Object(1);

          Object & * b = a;

          這里的b就等于是a的另外一個別名,b就是a。對b賦值就等于對a賦值。甚至作為參數傳遞時,也是如此。對這種類型的參數的賦值,就等于對外層函數數據的賦值。

          public class B{

          void func1(Object & * b){

                 b = new Object(4);

          }

           

          public void main(){

                 Object * a = new Object(1);

           

                 func1(a);

           

                 // a is changed to Object(4) now.

          }

           

          }

          當運行完func1(a);時,a的值變化為Object(4)。這是因為編譯器實際把參數Object & * b編譯為Object ** b_addrb_addr的值是b的地址,也就是a的地址。

          當調用func1()的時候,實際上是把b_addr作為參數壓到棧里,b_addr的值是a的地址。

          當執行b = new Object(4); 時,實際執行了 b_addr->b = new Object(4); 也就是執行了 b_addr->a = new Object(4); a的值當然變化了。

           

          還有一點需要說明,當使用COMCORBA等中間件規范進行開發時,我們需要定義IDL語言。參數的類型分為,[in][out][in, out],其中的RPC遠程調用的參數打包規范,就更復雜了,但原理卻是一樣的。

          posted on 2005-11-17 09:43 安德爾斯 閱讀(393) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 什邡市| 兴仁县| 荆州市| 临安市| 茶陵县| 上虞市| 濮阳市| 磴口县| 都安| 澄城县| 仙游县| 美姑县| 青海省| 太和县| 名山县| 商洛市| 凤冈县| 商都县| 庆元县| 顺义区| 土默特右旗| 固阳县| 崇明县| 吉安市| 曲周县| 北票市| 英超| 涿鹿县| 柳州市| 南召县| 太仓市| 安化县| 平远县| 金湖县| 泸西县| 凉城县| 安陆市| 陇川县| 微博| 舟山市| 连平县|