Java,J2EE,Weblogic,Oracle

          java項目隨筆
          隨筆 - 90, 文章 - 6, 評論 - 61, 引用 - 0
          數據加載中……

          java 值傳遞 引用傳遞

          Java代碼
          public class ParamTest {  
              // 初始值為0  
              protected int num = 0;  
           
              // 為方法參數重新賦值  
              public void change(int i) {  
                  i = 5;  
              }  
           
              // 為方法參數重新賦值  
              public void change(ParamTest t) {  
                  ParamTest tmp = new ParamTest();  
                  tmp.num = 9;  
                  t = tmp;  
              }  
           
              // 改變方法參數的值  
              public void add(int i) {  
                  i += 10;  
              }  
           
              // 改變方法參數屬性的值  
              public void add(ParamTest pt) {  
                  pt.num += 20;  
              }  
           
              public static void main(String[] args) {  
                  ParamTest t = new ParamTest();  
           
                  System.out.println("參數--基本類型");  
                  System.out.println("原有的值:" + t.num);  
                  // 為基本類型參數重新賦值  
                  t.change(t.num);  
                  System.out.println("賦值之后:" + t.num);  
                  // 為引用型參數重新賦值  
                  t.change(t);  
                  System.out.println("運算之后:" + t.num);  
           
                  System.out.println();  
           
                  t = new ParamTest();  
                  System.out.println("參數--引用類型");  
                  System.out.println("原有的值:" + t.num);  
                  // 改變基本類型參數的值  
                  t.add(t.num);  
                  System.out.println("賦引用后:" + t.num);  
                  // 改變引用類型參數所指向對象的屬性值  
                  t.add(t);  
                  System.out.println("改屬性后:" + t.num);  
              }  

          這段代碼的運行結果如下:

          參數--基本類型
          原有的值:0
          賦值之后:0
          運算之后:0

          參數--引用類型
          原有的值:0
          賦引用后:0
          改屬性后:20

          從上面這個直觀的結果中我們很容易得出如下結論:

          對于基本類型,在方法體內對方法參數進行重新賦值,并不會改變原有變量的值。
          對于引用類型,在方法體內對方法參數進行重新賦予引用,并不會改變原有變量所持有的引用。
          方法體內對參數進行運算,不影響原有變量的值。
          方法體內對參數所指向對象的屬性進行運算,將改變原有變量所指向對象的屬性值。

          上面總結出來的不過是我們所看到的表面現象。那么,為什么會出現這樣的現象呢?這就要說到值傳遞和引用傳遞的概念了。這個問題向來是頗有爭議的。

          大家都知道,在JAVA中變量有以下兩種:

          基本類型變量,包括char、byte、short、int、long、float、double、boolean。
          引用類型變量,包括類、接口、數組(基本類型數組和對象數組)。

          當基本類型的變量被當作參數傳遞給方法時,JAVA虛擬機所做的工作是把這個值拷貝了一份,然后把拷貝后的值傳遞到了方法的內部。因此在上面的例子中,我們回頭來看看這個方法:
          Java代碼 
          // 為方法參數重新賦值   
          public   void  change( int  i) {  
              i = 5 ;  
          }  
          Java代碼
          // 為方法參數重新賦值  
          public void change(int i) {  
              i = 5;  

           // 為方法參數重新賦值
           public void change(int i) {
            i = 5;
           }

          在這個方法被調用時,變量i和ParamTest型對象t的屬性num具有相同的值,卻是兩個不同變量。變量i是由JAVA虛擬機創建的作用域在 change(int i)方法內的局部變量,在這個方法執行完畢后,它的生命周期就結束了。在JAVA虛擬機中,它們是以類似如下的方式存儲的:

           

          很明顯,在基本類型被作為參數傳遞給方式時,是值傳遞,在整個過程中根本沒有牽扯到引用這個概念。這也是大家所公認的。對于布爾型變量當然也是如此,請看下面的例子:
          Java代碼 
          public   class  BooleanTest {  
              // 布爾型值   
              boolean  bool =  true ;  
            
              // 為布爾型參數重新賦值   
              public   void  change( boolean  b) {  
                  b = false ;  
              }  
            
              // 對布爾型參數進行運算   
              public   void  calculate( boolean  b) {  
                  b = b && false ;  
                  // 為了方便對比,將運算結果輸出   
                  System.out.println("b運算后的值:"  + b);  
              }  
            
              public   static   void  main(String[] args) {  
                  BooleanTest t = new  BooleanTest();  
            
                  System.out.println("參數--布爾型" );  
                  System.out.println("原有的值:"  + t.bool);  
                  // 為布爾型參數重新賦值   
                  t.change(t.bool);  
                  System.out.println("賦值之后:"  + t.bool);  
            
                  // 改變布爾型參數的值   
                  t.calculate(t.bool);  
                  System.out.println("運算之后:"  + t.bool);  
              }  
          }  
          Java代碼
          public class BooleanTest {  
              // 布爾型值  
              boolean bool = true;  
           
              // 為布爾型參數重新賦值  
              public void change(boolean b) {  
                  b = false;  
              }  
           
              // 對布爾型參數進行運算  
              public void calculate(boolean b) {  
                  b = b && false;  
                  // 為了方便對比,將運算結果輸出  
                  System.out.println("b運算后的值:" + b);  
              }  
           
              public static void main(String[] args) {  
                  BooleanTest t = new BooleanTest();  
           
                  System.out.println("參數--布爾型");  
                  System.out.println("原有的值:" + t.bool);  
                  // 為布爾型參數重新賦值  
                  t.change(t.bool);  
                  System.out.println("賦值之后:" + t.bool);  
           
                  // 改變布爾型參數的值  
                  t.calculate(t.bool);  
                  System.out.println("運算之后:" + t.bool);  
              }  

          public class BooleanTest {
           // 布爾型值
           boolean bool = true;

           // 為布爾型參數重新賦值
           public void change(boolean b) {
            b = false;
           }

           // 對布爾型參數進行運算
           public void calculate(boolean b) {
            b = b && false;
            // 為了方便對比,將運算結果輸出
            System.out.println("b運算后的值:" + b);
           }

           public static void main(String[] args) {
            BooleanTest t = new BooleanTest();

            System.out.println("參數--布爾型");
            System.out.println("原有的值:" + t.bool);
            // 為布爾型參數重新賦值
            t.change(t.bool);
            System.out.println("賦值之后:" + t.bool);

            // 改變布爾型參數的值
            t.calculate(t.bool);
            System.out.println("運算之后:" + t.bool);
           }
          }

          輸出結果如下:

          參數--布爾型
          原有的值:true
          賦值之后:true
          b運算后的值:false
          運算之后:true

          那么當引用型變量被當作參數傳遞給方法時JAVA虛擬機又是怎樣處理的呢?同樣,它會拷貝一份這個變量所持有的引用,然后把它傳遞給JAVA虛擬機為方法創建的局部變量,從而這兩個變量指向了同一個對象。在篇首所舉的示例中,ParamTest類型變量t和局部變量pt在JAVA虛擬機中是以如下的方式存儲的:

           

          有一種說法是當一個對象或引用類型變量被當作參數傳遞時,也是值傳遞,這個值就是對象的引用,因此JAVA中只有值傳遞,沒有引用傳遞。還有一種說法是引用可以看作是對象的別名,當對象被當作參數傳遞給方法時,傳遞的是對象的引用,因此是引用傳遞。這兩種觀點各有支持者,但是前一種觀點被絕大多數人所接受,其中有《Core Java》一書的作者,以及JAVA的創造者James Gosling,而《Thinking in Java》一書的作者Bruce Eckel則站在了中立的立場上。

          我個人認為值傳遞中的值指的是基本類型的數值,即使對于布爾型,雖然它的表現形式為true和false,但是在棧中,它仍然是以數值形式保存的,即0表示false,其它數值表示true。而引用是我們用來操作對象的工具,它包含了對象在堆中保存地址的信息。即使在被作為參數傳遞給方法時,實際上傳遞的是它的拷貝,但那仍是引用。因此,用引用傳遞來區別與值傳遞,概念上更加清晰。

          最后我們得出如下的結論:

          基本類型和基本類型變量被當作參數傳遞給方法時,是值傳遞。在方法實體中,無法給原變量重新賦值,也無法改變它的值。
          對象和引用型變量被當作參數傳遞給方法時,在方法實體中,無法給原變量重新賦值,但是可以改變它所指向對象的屬性。至于到底它是值傳遞還是引用傳遞,這并不重要,重要的是我們要清楚當一個引用被作為參數傳遞給一個方法時,在這個方法體內會發生什么。

          基本類型:int,float,byte,short,char,double,string,long傳值。
          其它對象類型:傳引用。
          在你的方法g里面,int num是是基本類型,傳值,ParamTest tmp 是對象,傳引用。

          posted on 2008-10-05 03:11 龔椿深 閱讀(3255) 評論(3)  編輯  收藏

          評論

          # re: java 值傳遞 引用傳遞   回復  更多評論   

          寫的很經典,今天拜讀了,謝謝
          2009-03-10 22:25 | jackee

          # re: java 值傳遞 引用傳遞   回復  更多評論   

          很詳細,很清晰~~謝謝了!
          2011-07-13 16:34 | yfx

          # re: java 值傳遞 引用傳遞 [未登錄]  回復  更多評論   

          。。。很好。。。在加一條:對象和引用型變量被當作參數傳遞給方法時,在方法實體中,無法給原變量重新賦值,但是可以改變它所指向對象的屬性。。。。。。。。。。。。。。。。。。。。。關鍵在于怎么改變,要調用對象或者引用變量內部的方法去改變,才能真正的改變。。比如,用=號修改,是不能改變的,
          2012-05-20 11:59 | QQ

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


          網站導航:
           
          主站蜘蛛池模板: 洪江市| 金溪县| 越西县| 阳城县| 安义县| 海淀区| 临湘市| 弥勒县| 连云港市| 五家渠市| 逊克县| 焦作市| 延长县| 陇南市| 柳林县| 伊通| 临漳县| 翁源县| 仙游县| 牡丹江市| 讷河市| 五家渠市| 南充市| 靖安县| 曲阳县| 彝良县| 中方县| 邮箱| 梁平县| 临泉县| 荔波县| 信阳市| 沁源县| 井冈山市| 宜良县| 镶黄旗| 额尔古纳市| 杭锦后旗| 黑水县| 库尔勒市| 衡水市|