posts - 73,  comments - 55,  trackbacks - 0
          JAVA中的傳遞都是值傳遞嗎?有沒有引用傳遞呢?

          在回答這兩個問題前,讓我們首先來看一段代碼:
          Java代碼 復制代碼
          1. public class ParamTest {   
          2.     // 初始值為0   
          3.     protected int num = 0;   
          4.   
          5.     // 為方法參數重新賦值   
          6.     public void change(int i) {   
          7.          i = 5;   
          8.      }   
          9.   
          10.     // 為方法參數重新賦值   
          11.     public void change(ParamTest t) {   
          12.          ParamTest tmp = new ParamTest();   
          13.          tmp.num = 9;   
          14.          t = tmp;   
          15.      }   
          16.   
          17.     // 改變方法參數的值   
          18.     public void add(int i) {   
          19.          i += 10;   
          20.      }   
          21.   
          22.     // 改變方法參數屬性的值   
          23.     public void add(ParamTest pt) {   
          24.          pt.num += 20;   
          25.      }   
          26.   
          27.     public static void main(String[] args) {   
          28.          ParamTest t = new ParamTest();   
          29.   
          30.          System.out.println("參數--基本類型");   
          31.          System.out.println("原有的值:" + t.num);   
          32.         // 為基本類型參數重新賦值   
          33.          t.change(t.num);   
          34.          System.out.println("賦值之后:" + t.num);   
          35.         // 為引用型參數重新賦值   
          36.          t.change(t);   
          37.          System.out.println("運算之后:" + t.num);   
          38.   
          39.          System.out.println();   
          40.   
          41.          t = new ParamTest();   
          42.          System.out.println("參數--引用類型");   
          43.          System.out.println("原有的值:" + t.num);   
          44.         // 改變基本類型參數的值   
          45.          t.add(t.num);   
          46.          System.out.println("賦引用后:" + t.num);   
          47.         // 改變引用類型參數所指向對象的屬性值   
          48.          t.add(t);   
          49.          System.out.println("改屬性后:" + t.num);   
          50.      }   
          51. }  

          這段代碼的運行結果如下:
          1. 參數--基本類型
          2. 原有的值:0
          3. 賦值之后:0
          4. 運算之后:0

          5. 參數--引用類型
          6. 原有的值:0
          7. 賦引用后:0
          8. 改屬性后:20

          從上面這個直觀的結果中我們很容易得出如下結論:
          1. 對于基本類型,在方法體內對方法參數進行重新賦值,并不會改變原有變量的值。
          2. 對于引用類型,在方法體內對方法參數進行重新賦予引用,并不會改變原有變量所持有的引用。
          3. 方法體內對參數進行運算,不影響原有變量的值。
          4. 方法體內對參數所指向對象的屬性進行運算,將改變原有變量所指向對象的屬性值。

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

          大家都知道,在JAVA中變量有以下兩種:
          1. 基本類型變量,包括char、byte、short、int、long、float、double、boolean。
          2. 引用類型變量,包括類、接口、數組(基本類型數組和對象數組)。

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

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

          很明顯,在基本類型被作為參數傳遞給方式時,是值傳遞,在整個過程中根本沒有牽扯到引用這個概念。這也是大家所公認的。對于布爾型變量當然也是如此,請看下面的例子:
          Java代碼 復制代碼
          1. public class BooleanTest {   
          2.     // 布爾型值   
          3.     boolean bool = true;   
          4.   
          5.     // 為布爾型參數重新賦值   
          6.     public void change(boolean b) {   
          7.          b = false;   
          8.      }   
          9.   
          10.     // 對布爾型參數進行運算   
          11.     public void calculate(boolean b) {   
          12.          b = b && false;   
          13.         // 為了方便對比,將運算結果輸出   
          14.          System.out.println("b運算后的值:" + b);   
          15.      }   
          16.   
          17.     public static void main(String[] args) {   
          18.          BooleanTest t = new BooleanTest();   
          19.   
          20.          System.out.println("參數--布爾型");   
          21.          System.out.println("原有的值:" + t.bool);   
          22.         // 為布爾型參數重新賦值   
          23.          t.change(t.bool);   
          24.          System.out.println("賦值之后:" + t.bool);   
          25.   
          26.         // 改變布爾型參數的值   
          27.          t.calculate(t.bool);   
          28.          System.out.println("運算之后:" + t.bool);   
          29.      }   
          30. }  

          輸出結果如下:
          1. 參數--布爾型
          2. 原有的值:true
          3. 賦值之后:true
          4. b運算后的值:false
          5. 運算之后:true

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

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

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

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

          什么叫引用?只因為這個變量的值和其它的不一樣.


          首先理解:都是變量
          int i;
          ArrayList b;
          i和b都是變量.
          但i是基本變量,也叫原始變量.
          其它的就叫引用變量,因為它的值是一個內存地址值.引用對象的.但記住:它們都是有一個值的!i是一個數字,而b是一個內存地址值(簡單的說是一個十六進 制的值).除了基本變量之外的變量都是引用變量.Vector a;這里的a也是一個變量.它也是有值的,它的值是一個十六進制的值.

          變量的賦值:
          int i=10;
          int j=i;
          //這里把i的值10給了j,所以j的值也是10

          ArrayList b=new ArrayList();
          ArrayList c=b;
          //首先,b是一個引用變量,它的"值":是一個內存地址值!!! new ArrayList()要分配一段內存保存它們,怎么樣找到這段內存?那就是通過b里的值了.b的值就是new ArrayList()所占內存的首地址.然后c也是一個引用變量,它的值(地址值)和b是一樣的.也就是new ArrayList()所占內存的首地址.所以當通過b或者c進行操作時,它們都是操作同一個對象的.

          在方法調用的時候,方法的參數實際也就是一個變量.如果是基本類型變量的時候,假設有方法method(int aa);
          int j=10;
          method(j);
          這里邊,int aa實際也是定義了一個變量,調用的時候把j的值:10也給了aa.所以aa也是10,改變了aa的值并不會改變j的值.

          如果是引用變量的時候,假設有方法methodA(ArrayList aa);
          ArrayList b = new ArrayList();
          methodA(b);
          //方法定義了變量aa,調用的時候把b的值(地址值!!!!!)給了aa,所以aa與b有一樣的值(地址值!!!!),在方法里通過aa去操作的時候,b所引用的對象也就被改變了,因為它們引用同一個對象.

          紙 a = new 銀行帳戶();//開一個銀行帳戶,返回一個卡號給你,寫在你的紙a里邊.

          用一張紙(引用變量),把你的銀行卡號寫在上邊,然后調用我的時候,我用另外一張紙(引用變量---方法的形數),把你的號碼抄過來.然后我通過這個卡號,去到銀行找到你的帳號,給你存點錢.

          然后你用你的紙(引用變量)上的卡號 <沒變,還是那個卡號>再去查詢銀行帳號的時候就會發現了多了一些錢了.....

          說說我對值傳遞和引用傳遞的看法:
          首先我認為,大家對Java傳遞參數的行為是清楚的,這個爭論只是一個語義上的爭論。
          也就是我們是否需要區分值傳遞和應用傳遞呢?或者說這樣的區分有沒有意義?是否合理?

          博主認為存在引用傳遞的關鍵點在于,傳遞的對象地址值,本質上它是一個引用,無論它是否被copy過。
          認為只有值傳遞的關鍵點在于,傳遞的對象地址值,它是一個值的copy,這個值代表的意義無所謂。

          引用是c++里的概念,由于java跟c++是有一定關系的,這里把引用遷移過來,如果合理未嘗不可。
          c++中關于引用的解釋一般喜歡說是看作“別名”,我查了幾本書,大部分提到引用并不會分配內存空間,也有一本書提到,某些編譯器會分配存儲空間來存儲被引用對象的地址。
          那么還是回到語義上來,c++里的這個引用,語義上是“別名”的意思,我的理解是,一組指向同一個對象的別名應該只存儲一份內存地址。當然具體實現可能會 把引用當做一個不可變的指針來處理(每個別名都存儲自己的對象地址)。但是請注意,我們應該關注于它的語義,即:它沒有任何值的copy,即使是一個地 址,只是另外一個名字而已。

          但是java里面沒有這樣的概念,所有的地址傳遞其行為是值的傳遞方式,語義上統一成值傳遞更為清晰,我們只需要考慮這個值具體是什么,無非兩種,要么是基本類型值,要么是個地址。
          所以我認為這個“引用”的概念放到java中并不合適。只有值傳遞的說法更合理。

          posted on 2008-09-12 10:25 保爾任 閱讀(3424) 評論(1)  編輯  收藏

          FeedBack:
          # re: java中到底傳值還是引用[未登錄]
          2009-04-07 22:32 | DAVID
          lz 在美國還在是祖國?  回復  更多評論
            

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


          網站導航:
           

          <2008年9月>
          31123456
          78910111213
          14151617181920
          21222324252627
          2829301234
          567891011

          常用鏈接

          留言簿(4)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 洱源县| 延安市| 旬邑县| 平罗县| 太康县| 千阳县| 神木县| 邯郸市| 莱芜市| 涟水县| 衢州市| 肇源县| 灯塔市| 宁夏| 三明市| 谷城县| 漠河县| 通渭县| 北流市| 乌海市| 永平县| 台前县| 财经| 石城县| 酒泉市| 北安市| 宁明县| 且末县| 漠河县| 博爱县| 华宁县| 印江| 嘉善县| 宾阳县| 德阳市| 得荣县| 绥江县| 峨眉山市| 三穗县| 柳州市| 上栗县|