<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中的傳遞都是值傳遞嗎?有沒有引用傳遞呢?

    在回答這兩個問題前,讓我們首先來看一段代碼:
    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 @ 2008-09-12 10:25 保爾任 閱讀(3432) | 評論 (1)編輯 收藏
    Linux 發展到今天,可用的軟件已經非常多了。這樣自然會有一些軟件的功能大致上相同。例如,同樣是編輯器,就有 nvi、vim、emacs、nano,而且我說的這些還只是一部分。大多數情況下,這樣的功能相似的軟件都是同時安裝在系統里的,可以用它們的名稱來執 行。例如,要執行 vim,只要在終端下輸入 vim 并按回車就可以了。不過,有些情況下我們需要用一個相對固定的命令調用這些程序中的一個。例如,當我們寫一個腳本程序時,只要寫下 editor,而不希望要為“編輯器是哪個”而操心。Debian 提供了一種機制來解決這個問題,而 update-alternatives 就是用來實現這種機制的。

    在說明 update-alternatives 的詳細內容之間,先讓我們看看系統中已有的例子。打開終端,執行下面的命令:

    herbert@natsu:~$ ls -l /usr/bin/editor
    lrwxrwxrwx 1 root root 24 2004-09-26 08:48 /usr/bin/editor -> /etc/alternatives/editor
    herbert@natsu:~$ ls -l /etc/alternatives/editor
    lrwxrwxrwx 1 root root 12 2004-10-27 16:24 /etc/alternatives/editor -> /usr/bin/vim
    herbert@natsu:~$

    我 們看到,editor 這個可執行命令實際上是個符號鏈接,它指向 /etc/alternatives/editor;而 /etc/alternatives/editor 也是個符號鏈接,它指向 /usr/bin/vim。這樣,當我輸入 editor 并回車時,將執行 vim。之所以要在 /usr/bin 和 /etc/alternatives 中費心建立這樣兩個鏈接,就是要實現上面說到的特性:方便腳本
    程序的編寫和系統的管理。

    下面我們就來看看 update-alternatives 的功能。當然,如果你覺得我說得不詳細,可以看看這個命令的 manpage:UPDATE-ALTERNATIVES(8)。

    首先要介紹的參數是 --display。它使我們可以看到一個命令的所有可選命令。執行

    natsu:/home/herbert# update-alternatives --display editor
    editor - status is auto.
     link currently points to /usr/bin/vim
    /bin/ed - priority -100
     slave editor.1.gz: /usr/share/man/man1/ed.1.gz
    /usr/bin/nvi - priority 19
     slave editor.1.gz: /usr/share/man/man1/nvi.1.gz
    /bin/nano - priority 40
     slave editor.1.gz: /usr/share/man/man1/nano.1.gz
    /usr/bin/vim - priority 120
     slave editor.1.gz: /usr/share/man/man1/vim.1.gz
    /usr/bin/emacs21 - priority 0
     slave editor.1.gz: /usr/share/man/man1/emacs.1emacs21.gz
    Current `best' version is /usr/bin/vim.
    natsu:/home/herbert#

    你可以看到我的機器上的所有可以用來被 editor 鏈接的命令。

    下面說說 --config。這個選項使我們可以選擇其中一個命令:

    natsu:/home/herbert# update-alternatives --config editor

    There are 5 alternatives which provide `editor'.

      Selection Alternative
    -----------------------------------------------
          1 /bin/ed
          2 /usr/bin/nvi
          3 /bin/nano
    *+    4 /usr/bin/vim
          5 /usr/bin/emacs21

    Press enter to keep the default[*], or type selection number: 4
    Using `/usr/bin/vim' to provide `editor'.
    natsu:/home/herbert#

    我并沒有修改它,因為我還是比較喜歡 vim 的。當然,你可以選擇別的程序。

    說 到這里我們就要介紹一些概念了。首先,update-alternatives 在一般情況下是由 postinst 和 prerm 這樣的安裝腳本自動調用的,所以一個 alternative 的狀態有兩種:自動和手動。每個 alternative 的初始狀態都是自動。如果系統發現管理員手動修改了一個 alternative,它的狀態就從自動變成了手動,這樣安裝腳本就不會更新它了。如果你希望將一個 alternative 變回自動,只要執行

    update-alternatives --auto editor

    就可以了。你注意到了嗎?我們說到了“名字”。該怎樣寫名字呢?這就是我們要介紹的第二個概念:
    general name -- 這是指一系列功能相似的程序的“公用”名字(包括絕對路徑),比如 /usr/bin/editor。
    link -- 這是指一個 alternative 在 /etc/alternative 中的名字,比如 editor。
    alternative -- 顧名思義,這是指一個可選的程序所在的路徑(包括絕對路徑),比如 /usr/bin/vim。
    -- auto,--display 和 --config 跟的都是 link。我們要說的第三個概念是優先級。這個比較簡單,當然優先級越高的程序越好啦(在大多數情況下,我不想爭論)最后一個概念是主和從的 alternative。想想看,你將 /usr/bin/editor 鏈接到了 vim,可是當你執行 man editor 時看到的卻是 emacs 的 manpage,你會做何感想呢?這就引出了主和從 alternative 的概念了:當更新主的 alternative 時,從的 alternative 也會被更新。

    說完這四個重要的概念后,我們介紹另外兩個選項。至于其他的。。。。我相信你會去看手冊頁的,對嗎?

    第一個是 --install。它的格式是:

    update-alternatives --install gen link alt pri [--slave sgen slink salt] ...

    gen, link,alt,pri 分別是我們上面說過的。如果需要從的 alternative,你可以用 --slave 加在后面。如果你在向一個已經存在的 alternative 組中添加新的 alternatives,該命令會把這些 alternatives 加入到這個已經存在的 alternative 組的
    列表中,并用新的可選命令作為新的命令;否則,將會建立一個新的自動的 alternative 組。

    嗚呼!我加入了一個錯誤的 alternative。我不想要這個 alternative 了。在這種情況 下,可以執行下面的命令:

    update-alternatives --remove name path

    name 是一個在 /etc/alternatives 中的名字,也就是上面的 link,而 path 是希望刪除的可選程序名的絕對路徑名(放心,這樣只是從列表中刪除了這個程序,并不會真的從硬盤上刪除程序的可執行文件)。如果從一個 alternative 組中刪除了一個正在被鏈接的程序并且這個組仍然沒有變成空的,update-alternatives 會自動用一個具有其他優先級的可選程序代替原來的程序。如果這個組變成空的了,那么連這個 alternative 組都會被移除。如果刪除的程序沒有被鏈接,則只有有關這個程序的信息會被移除。

    說個例子吧。我下載了 Eclipse,并且安裝了 gcj 和 gij。可是我發現 GNU 的 java 工具還不足以運行 Eclipse。我只好到 Sun 公司的網頁上下載了它的 java 工具 jdk。因為是自己安裝的,我將它們安裝在 /usr/local 上,以便將來重新安裝 Linux 系統時這些程序仍然可以使用。于是我要做的就是用這個 jdk 中的 java 和 javac 來代替系統原來的。執行

    natsu:/home/herbert# update-alternatives --display java
    java - status is auto.
     link currently points to /usr/local/j2sdk1.4.2_06/bin/java
    /usr/bin/gij-wrapper-3.3 - priority 33
     slave java.1.gz: /usr/share/man/man1/gij-wrapper-3.3.1.gz
    /usr/local/j2sdk1.4.2_06/bin/java - priority 100
     slave java.1.gz: /usr/local/j2sdk1.4.2_06/man/man1/java.1
    Current `best' version is /usr/local/j2sdk1.4.2_06/bin/java.
    natsu:/home/herbert# update-alternatives --display javac
    javac - status is auto.
     link currently points to /usr/local/j2sdk1.4.2_06/bin/javac
    /usr/bin/gcj-wrapper-3.3 - priority 33
     slave javah: /usr/bin/gcjh-wrapper-3.3
     slave javac.1.gz: /usr/share/man/man1/gcj-wrapper-3.3.1.gz
     slave javah.1.gz: /usr/share/man/man1/gcjh-wrapper-3.3.1.gz
    /usr/bin/gcj-wrapper-3.4 - priority 33
     slave javah: /usr/bin/gcjh-wrapper-3.4
     slave javac.1.gz: /usr/share/man/man1/gcj-wrapper-3.4.1.gz
     slave javah.1.gz: /usr/share/man/man1/gcjh-wrapper-3.4.1.gz
    /usr/local/j2sdk1.4.2_06/bin/javac - priority 100
     slave javah: /usr/local/j2sdk1.4.2_06/bin/javah
     slave javac.1.gz: /usr/local/j2sdk1.4.2_06/man/man1/javac.1
     slave javah.1.gz: /usr/local/j2sdk1.4.2_06/man/man1/javah.1
    Current `best' version is /usr/local/j2sdk1.4.2_06/bin/javac.
    natsu:/home/herbert#

    (你看到的是我更新以后的)就可以得到關于要更新哪些 alternatives 的信息。我是這么更新的:

    update-alternatives --install /usr/bin/javac javac /usr/local/j2sdk1.4.2_06/bin/javac 100 --slave /usr/bin/javah javah /usr/local/j2sdk1.4.2_06/bin/javah --slave /usr/share/man/man1/javac.1.gz javac.1.gz /usr/local/j2sdk1.4.2_06/man/man1/javac.1 --slave /usr/share/man/man1/javah.1.gz javah.1.gz /usr/local/j2sdk1.4.2_06/man/man1/javah.1
    update-alternatives --install /usr/bin/java java /usr/local/j2sdk1.4.2_06/bin/java 100 --slave /usr/share/man/man1/java.1.gz java.1.gz /usr/local/j2sdk1.4.2_06/man/man1/java.1
    posted @ 2008-02-13 10:08 保爾任 閱讀(2583) | 評論 (0)編輯 收藏

    <2008年2月>
    272829303112
    3456789
    10111213141516
    17181920212223
    2425262728291
    2345678

    常用鏈接

    留言簿(4)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 四虎影视成人永久免费观看视频 | 老司机午夜性生免费福利| 亚洲欧美日韩一区二区三区| 男男gvh肉在线观看免费| 成人免费午夜无码视频| 免费二级毛片免费完整视频| 国产精品亚洲αv天堂无码| 色欲aⅴ亚洲情无码AV| 四虎影在线永久免费四虎地址8848aa | 亚洲国产一成久久精品国产成人综合| AV激情亚洲男人的天堂国语| 国产免费啪嗒啪嗒视频看看| 阿v视频免费在线观看| 亚洲精品国产日韩无码AV永久免费网| 一级毛片视频免费观看| 亚洲中文无码永久免费| 亚洲欧洲免费无码| 亚洲精品偷拍视频免费观看| 久久不见久久见免费影院www日本| 中文字幕精品亚洲无线码一区应用| 亚洲精品中文字幕无乱码| 真人做A免费观看| 亚洲深深色噜噜狠狠爱网站| 亚洲中文字幕乱码一区| a级成人毛片免费图片| 暖暖免费高清日本中文| 一级片在线免费看| 久久丫精品国产亚洲av不卡| 在线观看特色大片免费视频| 日本亚洲中午字幕乱码| 亚洲精品乱码久久久久久久久久久久 | 国产男女猛烈无遮档免费视频网站| 亚洲图片在线观看| 最近高清国语中文在线观看免费| 五月天网站亚洲小说| 最近最新MV在线观看免费高清| 国产精品亚洲色婷婷99久久精品| 亚洲精品乱码久久久久66| AA免费观看的1000部电影| 免费看黄网站在线看| 巨胸喷奶水视频www网免费|