<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

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

    在回答這兩個(gè)問(wèn)題前,讓我們首先來(lái)看一段代碼:
    Java代碼 復(fù)制代碼
    1. public class ParamTest {   
    2.     // 初始值為0   
    3.     protected int num = 0;   
    4.   
    5.     // 為方法參數(shù)重新賦值   
    6.     public void change(int i) {   
    7.          i = 5;   
    8.      }   
    9.   
    10.     // 為方法參數(shù)重新賦值   
    11.     public void change(ParamTest t) {   
    12.          ParamTest tmp = new ParamTest();   
    13.          tmp.num = 9;   
    14.          t = tmp;   
    15.      }   
    16.   
    17.     // 改變方法參數(shù)的值   
    18.     public void add(int i) {   
    19.          i += 10;   
    20.      }   
    21.   
    22.     // 改變方法參數(shù)屬性的值   
    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("參數(shù)--基本類型");   
    31.          System.out.println("原有的值:" + t.num);   
    32.         // 為基本類型參數(shù)重新賦值   
    33.          t.change(t.num);   
    34.          System.out.println("賦值之后:" + t.num);   
    35.         // 為引用型參數(shù)重新賦值   
    36.          t.change(t);   
    37.          System.out.println("運(yùn)算之后:" + t.num);   
    38.   
    39.          System.out.println();   
    40.   
    41.          t = new ParamTest();   
    42.          System.out.println("參數(shù)--引用類型");   
    43.          System.out.println("原有的值:" + t.num);   
    44.         // 改變基本類型參數(shù)的值   
    45.          t.add(t.num);   
    46.          System.out.println("賦引用后:" + t.num);   
    47.         // 改變引用類型參數(shù)所指向?qū)ο蟮膶傩灾?  
    48.          t.add(t);   
    49.          System.out.println("改屬性后:" + t.num);   
    50.      }   
    51. }  

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

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

    從上面這個(gè)直觀的結(jié)果中我們很容易得出如下結(jié)論:
    1. 對(duì)于基本類型,在方法體內(nèi)對(duì)方法參數(shù)進(jìn)行重新賦值,并不會(huì)改變?cè)凶兞康闹怠?/li>
    2. 對(duì)于引用類型,在方法體內(nèi)對(duì)方法參數(shù)進(jìn)行重新賦予引用,并不會(huì)改變?cè)凶兞克钟械囊谩?/li>
    3. 方法體內(nèi)對(duì)參數(shù)進(jìn)行運(yùn)算,不影響原有變量的值。
    4. 方法體內(nèi)對(duì)參數(shù)所指向?qū)ο蟮膶傩赃M(jìn)行運(yùn)算,將改變?cè)凶兞克赶驅(qū)ο蟮膶傩灾怠?/li>

    上面總結(jié)出來(lái)的不過(guò)是我們所看到的表面現(xiàn)象。那么,為什么會(huì)出現(xiàn)這樣的現(xiàn)象呢?這就要說(shuō)到值傳遞和引用傳遞的概念了。這個(gè)問(wèn)題向來(lái)是頗有爭(zhēng)議的。

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

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

    在這個(gè)方法被調(diào)用時(shí),變量i和ParamTest型對(duì)象t的屬性num具有相同的值,卻是兩個(gè)不同變量。變量i是由JAVA虛擬機(jī)創(chuàng)建的作用域在 change(int i)方法內(nèi)的局部變量,在這個(gè)方法執(zhí)行完畢后,它的生命周期就結(jié)束了。在JAVA虛擬機(jī)中,它們是以類似如下的方式存儲(chǔ)的:

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

    輸出結(jié)果如下:
    1. 參數(shù)--布爾型
    2. 原有的值:true
    3. 賦值之后:true
    4. b運(yùn)算后的值:false
    5. 運(yùn)算之后:true

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

    有一種說(shuō)法是當(dāng)一個(gè)對(duì)象或引用類型變量被當(dāng)作參數(shù)傳遞時(shí),也是值傳遞,這個(gè)值就是對(duì)象的引用,因此JAVA中只有值傳遞,沒(méi)有引用傳遞。還有一種說(shuō)法是引 用可以看作是對(duì)象的別名,當(dāng)對(duì)象被當(dāng)作參數(shù)傳遞給方法時(shí),傳遞的是對(duì)象的引用,因此是引用傳遞。這兩種觀點(diǎn)各有支持者,但是前一種觀點(diǎn)被絕大多數(shù)人所接 受,其中有《Core Java》一書(shū)的作者,以及JAVA的創(chuàng)造者James Gosling,而《Thinking in Java》一書(shū)的作者Bruce Eckel則站在了中立的立場(chǎng)上。

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

    最后我們得出如下的結(jié)論:
    1. 基本類型和基本類型變量被當(dāng)作參數(shù)傳遞給方法時(shí),是值傳遞。在方法實(shí)體中,無(wú)法給原變量重新賦值,也無(wú)法改變它的值。
    2. 對(duì)象和引用型變量被當(dāng)作參數(shù)傳遞給方法時(shí),在方法實(shí)體中,無(wú)法給原變量重新賦值,但是可以改變它所指向?qū)ο蟮膶傩浴V劣诘降姿侵祩鬟f還是引用傳遞,這并不重要,重要的是我們要清楚當(dāng)一個(gè)引用被作為參數(shù)傳遞給一個(gè)方法時(shí),在這個(gè)方法體內(nèi)會(huì)發(fā)生什么。

    什么叫引用?只因?yàn)檫@個(gè)變量的值和其它的不一樣.


    首先理解:都是變量
    int i;
    ArrayList b;
    i和b都是變量.
    但i是基本變量,也叫原始變量.
    其它的就叫引用變量,因?yàn)樗闹凳且粋€(gè)內(nèi)存地址值.引用對(duì)象的.但記住:它們都是有一個(gè)值的!i是一個(gè)數(shù)字,而b是一個(gè)內(nèi)存地址值(簡(jiǎn)單的說(shuō)是一個(gè)十六進(jìn) 制的值).除了基本變量之外的變量都是引用變量.Vector a;這里的a也是一個(gè)變量.它也是有值的,它的值是一個(gè)十六進(jìn)制的值.

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

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

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

    如果是引用變量的時(shí)候,假設(shè)有方法methodA(ArrayList aa);
    ArrayList b = new ArrayList();
    methodA(b);
    //方法定義了變量aa,調(diào)用的時(shí)候把b的值(地址值!!!!!)給了aa,所以aa與b有一樣的值(地址值!!!!),在方法里通過(guò)aa去操作的時(shí)候,b所引用的對(duì)象也就被改變了,因?yàn)樗鼈円猛粋€(gè)對(duì)象.

    紙 a = new 銀行帳戶();//開(kāi)一個(gè)銀行帳戶,返回一個(gè)卡號(hào)給你,寫(xiě)在你的紙a里邊.

    用一張紙(引用變量),把你的銀行卡號(hào)寫(xiě)在上邊,然后調(diào)用我的時(shí)候,我用另外一張紙(引用變量---方法的形數(shù)),把你的號(hào)碼抄過(guò)來(lái).然后我通過(guò)這個(gè)卡號(hào),去到銀行找到你的帳號(hào),給你存點(diǎn)錢(qián).

    然后你用你的紙(引用變量)上的卡號(hào) <沒(méi)變,還是那個(gè)卡號(hào)>再去查詢銀行帳號(hào)的時(shí)候就會(huì)發(fā)現(xiàn)了多了一些錢(qián)了.....

    說(shuō)說(shuō)我對(duì)值傳遞和引用傳遞的看法:
    首先我認(rèn)為,大家對(duì)Java傳遞參數(shù)的行為是清楚的,這個(gè)爭(zhēng)論只是一個(gè)語(yǔ)義上的爭(zhēng)論。
    也就是我們是否需要區(qū)分值傳遞和應(yīng)用傳遞呢?或者說(shuō)這樣的區(qū)分有沒(méi)有意義?是否合理?

    博主認(rèn)為存在引用傳遞的關(guān)鍵點(diǎn)在于,傳遞的對(duì)象地址值,本質(zhì)上它是一個(gè)引用,無(wú)論它是否被copy過(guò)。
    認(rèn)為只有值傳遞的關(guān)鍵點(diǎn)在于,傳遞的對(duì)象地址值,它是一個(gè)值的copy,這個(gè)值代表的意義無(wú)所謂。

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

    但是java里面沒(méi)有這樣的概念,所有的地址傳遞其行為是值的傳遞方式,語(yǔ)義上統(tǒng)一成值傳遞更為清晰,我們只需要考慮這個(gè)值具體是什么,無(wú)非兩種,要么是基本類型值,要么是個(gè)地址。
    所以我認(rèn)為這個(gè)“引用”的概念放到j(luò)ava中并不合適。只有值傳遞的說(shuō)法更合理。

    posted @ 2008-09-12 10:25 保爾任 閱讀(3423) | 評(píng)論 (1)編輯 收藏

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

    常用鏈接

    留言簿(4)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    •  

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 456亚洲人成影院在线观| 日本系列1页亚洲系列| 毛片免费视频观看| 色一情一乱一伦一视频免费看| 亚洲午夜久久久久妓女影院| 很黄很黄的网站免费的| 午夜亚洲国产精品福利| 亚洲视频日韩视频| 亚洲精品无码久久不卡| 91精品免费在线观看| 一级特黄色毛片免费看| 亚洲13又紧又嫩又水多| 国产亚洲精品自在线观看| 最近免费中文字幕4| 国产在线观a免费观看| 亚洲欧美中文日韩视频| 亚洲精品免费在线观看| 免费大黄网站在线观| 69堂人成无码免费视频果冻传媒| www免费插插视频| 亚洲色欲色欱wwW在线| 亚洲va在线va天堂va不卡下载 | 亚洲免费人成在线视频观看| 亚洲欧美日本韩国| 亚洲视频在线观看不卡| 亚洲视频人成在线播放| 午夜色a大片在线观看免费| 最近中文字幕完整版免费高清| 一边摸一边爽一边叫床免费视频| 中国亚洲呦女专区| 91亚洲国产在人线播放午夜| 在线观看亚洲av每日更新| 国产成人免费全部网站| 日韩av无码成人无码免费| 黄页免费在线观看| 精品无码国产污污污免费网站国产 | 亚洲激情在线视频| 亚洲综合色婷婷七月丁香| 一本色道久久88综合亚洲精品高清| 国产成人免费午夜在线观看| 曰批全过程免费视频在线观看无码 |