• <label id="pxtpz"><meter id="pxtpz"></meter></label>
      1. <span id="pxtpz"><optgroup id="pxtpz"></optgroup></span>

        當(dāng)前位置:雨林木風(fēng)下載站 > 技術(shù)開(kāi)發(fā)教程 > 詳細(xì)頁(yè)面

        Java 應(yīng)用程序中的按值傳遞語(yǔ)義(轉(zhuǎn))

        Java 應(yīng)用程序中的按值傳遞語(yǔ)義(轉(zhuǎn))

        更新時(shí)間:2022-04-26 文章作者:未知 信息來(lái)源:網(wǎng)絡(luò) 閱讀次數(shù):

        Java 應(yīng)用程序中的按值傳遞語(yǔ)義
        原文http://www.cn.ibm.com/developerWorks/java/passbyval/index.shtml

        節(jié)選理解參數(shù)是按值而不是按引用傳遞的說(shuō)明 Java 應(yīng)用程序有且僅有的一種參數(shù)傳遞機(jī)制,即按值傳遞。寫(xiě)它是為了揭穿普遍存在的一種神話(huà),即認(rèn)為 Java 應(yīng)用程序按引用傳遞參數(shù),以避免因依賴(lài)“按引用傳遞”這一行為而導(dǎo)致的常見(jiàn)編程錯(cuò)誤。

        對(duì)此節(jié)選的某些反饋意見(jiàn)認(rèn)為,我把這一問(wèn)題搞糊涂了,或者將它完全搞錯(cuò)了。許多不同意我的讀者用 C++ 語(yǔ)言作為例子。因此,在此欄目中我將使用 C++ 和 Java 應(yīng)用程序進(jìn)一步闡明一些事實(shí)。

        要點(diǎn)
        讀完所有的評(píng)論以后,問(wèn)題終于明白了,至少在一個(gè)主要問(wèn)題上產(chǎn)生了混淆。某些評(píng)論認(rèn)為我的節(jié)選是錯(cuò)的,因?yàn)閷?duì)象是按引用傳遞的。對(duì)象確實(shí)是按引用傳遞的;節(jié)選與這沒(méi)有沖突。節(jié)選中說(shuō)所有參數(shù)都是按值 -- 另一個(gè)參數(shù) -- 傳遞的。下面的說(shuō)法是正確的:在 Java 應(yīng)用程序中永遠(yuǎn)不會(huì)傳遞對(duì)象,而只傳遞對(duì)象引用。因此是按引用傳遞對(duì)象。但重要的是要區(qū)分參數(shù)是如何傳遞的,這才是該節(jié)選的意圖。Java 應(yīng)用程序按引用傳遞對(duì)象這一事實(shí)并不意味著 Java 應(yīng)用程序按引用傳遞參數(shù)。參數(shù)可以是對(duì)象引用,而 Java 應(yīng)用程序是按值傳遞對(duì)象引用的。

        C++ 和 Java 應(yīng)用程序中的參數(shù)傳遞
        Java 應(yīng)用程序中的變量可以為以下兩種類(lèi)型之一:引用類(lèi)型或基本類(lèi)型。當(dāng)作為參數(shù)傳遞給一個(gè)方法時(shí),處理這兩種類(lèi)型的方式是相同的。兩種類(lèi)型都是按值傳遞的;沒(méi)有一種按引用傳遞。這是一個(gè)重要特性,正如隨后的代碼示例所示的那樣。

        在繼續(xù)討論之前,定義按值傳遞和按引用傳遞這兩個(gè)術(shù)語(yǔ)是重要的。按值傳遞意味著當(dāng)將一個(gè)參數(shù)傳遞給一個(gè)函數(shù)時(shí),函數(shù)接收的是原始值的一個(gè)副本。因此,如果函數(shù)修改了該參數(shù),僅改變副本,而原始值保持不變。按引用傳遞意味著當(dāng)將一個(gè)參數(shù)傳遞給一個(gè)函數(shù)時(shí),函數(shù)接收的是原始值的內(nèi)存地址,而不是值的副本。因此,如果函數(shù)修改了該參數(shù),調(diào)用代碼中的原始值也隨之改變。

        關(guān)于 Java 應(yīng)用程序中參數(shù)傳遞的某些混淆源于這樣一個(gè)事實(shí):許多程序員都是從 C++ 編程轉(zhuǎn)向 Java 編程的。C++ 既包含非引用類(lèi)型,又包含引用類(lèi)型,并分別按值和按引用傳遞它們。Java 編程語(yǔ)言有基本類(lèi)型和對(duì)象引用;因此,認(rèn)為 Java 應(yīng)用程序像 C++ 那樣對(duì)基本類(lèi)型使用按值傳遞,而對(duì)引用使用按引用傳遞是符合邏輯的。畢竟您會(huì)這么想,如果正在傳遞一個(gè)引用,則它一定是按引用傳遞的。很容易就會(huì)相信這一點(diǎn),實(shí)際上有一段時(shí)間我也相信是這樣,但這不正確。

        在 C++ 和 Java 應(yīng)用程序中,當(dāng)傳遞給函數(shù)的參數(shù)不是引用時(shí),傳遞的都是該值的一個(gè)副本(按值傳遞)。區(qū)別在于引用。在 C++ 中當(dāng)傳遞給函數(shù)的參數(shù)是引用時(shí),您傳遞的就是這個(gè)引用,或者內(nèi)存地址(按引用傳遞)。在 Java 應(yīng)用程序中,當(dāng)對(duì)象引用是傳遞給方法的一個(gè)參數(shù)時(shí),您傳遞的是該引用的一個(gè)副本(按值傳遞),而不是引用本身。請(qǐng)注意,調(diào)用方法的對(duì)象引用和副本都指向同一個(gè)對(duì)象。這是一個(gè)重要區(qū)別。Java 應(yīng)用程序在傳遞不同類(lèi)型的參數(shù)時(shí),其作法與 C++ 并無(wú)不同。Java 應(yīng)用程序按值傳遞所有參數(shù),這樣就制作所有參數(shù)的副本,而不管它們的類(lèi)型。

        示例
        我們將使用前面的定義和討論分析一些示例。首先考慮一段 C++ 代碼。C++ 語(yǔ)言同時(shí)使用按值傳遞和按引用傳遞的參數(shù)傳遞機(jī)制:

        清單 1:C++ 示例 #include
        #include

        void modify(int a, int *P, int &r);

        int main (int argc, char** argv)
        {
        int val, ref;
        int *pint;

        val = 10;
        ref = 50;
        pint = (int*)malloc(sizeof(int));
        *pint = 15;

        printf("val is %d\n", val);
        printf("pint is %d\n", pint);
        printf("*pint is %d\n", *pint);
        printf("ref is %d\n\n", ref);

        printf("calling modify\n");
        //按值傳遞 val 和 pint,按引用傳遞 ref。
        modify(val, pint, ref);
        printf("returned from modify\n\n");

        printf("val is %d\n", val);
        printf("pint is %d\n", pint);
        printf("*pint is %d\n", *pint);
        printf("ref is %d\n", ref);

        return 0;
        }

        void modify(int a, int *p, int &r)
        {
        printf("in modify...\n");
        a = 0;
        *p = 7;
        p = 0;
        r = 0;
        printf("a is %d\n", a);
        printf("p is %d\n", p);
        printf("r is %d\n", r);
        }




        這段代碼的輸出為:

        清單 2:C++ 代碼的輸出 val is 10
        pint is 4262128
        *pint is 15
        ref is 50

        calling modify
        in modify...
        a is 0
        p is 0
        r is 0
        returned from modify

        val is 10
        pint is 4262128
        *pint is 7
        ref is 0



        這段代碼聲明了三個(gè)變量:兩個(gè)整型變量和一個(gè)指針變量。設(shè)置了每個(gè)變量的初始值并將其打印出來(lái)。同時(shí)打印出了指針值及其所指向的值。然后將所有三個(gè)變量作為參數(shù)傳遞給 modify 函數(shù)。前兩個(gè)參數(shù)是按值傳遞的,最后一個(gè)參數(shù)是按引用傳遞的。modify 函數(shù)的函數(shù)原型表明最后一個(gè)參數(shù)要作為引用傳遞。回想一下,C++ 按值傳遞所有參數(shù),引用除外,后者是按引用傳遞的。

        modify 函數(shù)更改了所有三個(gè)參數(shù)的值:

        將第一個(gè)參數(shù)設(shè)置為 0。
        將第二個(gè)參數(shù)所指向的值設(shè)置為 7,然后將第二個(gè)參數(shù)設(shè)置為 0。
        將第三個(gè)參數(shù)設(shè)置為 0。

        將新值打印出來(lái),然后函數(shù)返回。當(dāng)執(zhí)行返回到 main 時(shí),再次打印出這三個(gè)參數(shù)的值以及指針?biāo)赶虻闹怠W鳛榈谝粋(gè)和第二個(gè)參數(shù)傳遞的變量不受 modify 函數(shù)的影響,因?yàn)樗鼈兪前粗祩鬟f的。但指針?biāo)赶虻闹蹈淖兞恕U?qǐng)注意,與前兩個(gè)參數(shù)不同,作為最后一個(gè)參數(shù)傳遞的變量被 modify 函數(shù)改變了,因?yàn)樗前匆脗鬟f的。

        現(xiàn)在考慮用 Java 語(yǔ)言編寫(xiě)的類(lèi)似代碼:

        清單 3:Java 應(yīng)用程序 class Test
        {
        public static void main(String args[])
        {
        int val;
        StringBuffer sb1, sb2;

        val = 10;
        sb1 = new StringBuffer("apples");
        sb2 = new StringBuffer("pears");
        System.out.println("val is " + val);
        System.out.println("sb1 is " + sb1);
        System.out.println("sb2 is " + sb2);
        System.out.println("");

        System.out.println("calling modify");
        //按值傳遞所有參數(shù)
        modify(val, sb1, sb2);
        System.out.println("returned from modify");
        System.out.println("");

        System.out.println("val is " + val);
        System.out.println("sb1 is " + sb1);
        System.out.println("sb2 is " + sb2);
        }

        public static void modify(int a, StringBuffer r1,
        StringBuffer r2)
        {
        System.out.println("in modify...");
        a = 0;
        r1 = null;//1
        r2.append(" taste good");
        System.out.println("a is " + a);
        System.out.println("r1 is " + r1);
        System.out.println("r2 is " + r2);
        }
        }



        這段代碼的輸出為:

        清單 4:Java 應(yīng)用程序的輸出 val is 10
        sb1 is apples
        sb2 is pears

        calling modify
        in modify...
        a is 0
        r1 is null
        r2 is pears taste good
        returned from modify

        val is 10
        sb1 is apples
        sb2 is pears taste good



        這段代碼聲明了三個(gè)變量:一個(gè)整型變量和兩個(gè)對(duì)象引用。設(shè)置了每個(gè)變量的初始值并將它們打印出來(lái)。然后將所有三個(gè)變量作為參數(shù)傳遞給 modify 方法。

        modify 方法更改了所有三個(gè)參數(shù)的值:

        將第一個(gè)參數(shù)(整數(shù))設(shè)置為 0。
        將第一個(gè)對(duì)象引用 r1 設(shè)置為 null。
        保留第二個(gè)引用 r2 的值,但通過(guò)調(diào)用 append 方法更改它所引用的對(duì)象(這與前面的 C++ 示例中對(duì)指針 p 的處理類(lèi)似)。

        當(dāng)執(zhí)行返回到 main 時(shí),再次打印出這三個(gè)參數(shù)的值。正如預(yù)期的那樣,整型的 val 沒(méi)有改變。對(duì)象引用 sb1 也沒(méi)有改變。如果 sb1 是按引用傳遞的,正如許多人聲稱(chēng)的那樣,它將為 null。但是,因?yàn)?Java 編程語(yǔ)言按值傳遞所有參數(shù),所以是將 sb1 的引用的一個(gè)副本傳遞給了 modify 方法。當(dāng) modify 方法在 //1 位置將 r1 設(shè)置為 null 時(shí),它只是對(duì) sb1 的引用的一個(gè)副本進(jìn)行了該操作,而不是像 C++ 中那樣對(duì)原始值進(jìn)行操作。

        另外請(qǐng)注意,第二個(gè)對(duì)象引用 sb2 打印出的是在 modify 方法中設(shè)置的新字符串。即使 modify 中的變量 r2 只是引用 sb2 的一個(gè)副本,但它們指向同一個(gè)對(duì)象。因此,對(duì)復(fù)制的引用所調(diào)用的方法更改的是同一個(gè)對(duì)象。

        編寫(xiě)一個(gè)交換方法
        假定我們知道參數(shù)是如何傳遞的,在 C++ 中編寫(xiě)一個(gè)交換函數(shù)可以用不同的方式完成。使用指針的交換函數(shù)類(lèi)似以下代碼,其中指針是按值傳遞的:

        清單 5:使用指針的交換函數(shù) #include
        #include

        void swap(int *a, int *b);

        int main (int argc, char** argv)
        {
        int val1, val2;
        val1 = 10;
        val2 = 50;
        swap(&val1, &val2);
        return 0;
        }

        void swap(int *a, int *b)
        {
        int temp = *b;
        *b = *a;
        *a = temp;
        }




        使用引用的交換函數(shù)類(lèi)似以下代碼,其中引用是按引用傳遞的:

        清單 6:使用引用的交換函數(shù) #include
        #include

        void swap(int &a, int &b);

        int main (int argc, char** argv)
        {
        int val1, val2;
        val1 = 10;
        val2 = 50;
        swap(val1, val2);
        return 0;
        }

        void swap(int &a, int &b)
        {
        int temp = b;
        b = a;
        a = temp;
        }



        兩個(gè) C++ 代碼示例都像所希望的那樣交換了值。如果 Java 應(yīng)用程序使用“按引用傳遞”,則下面的交換方法應(yīng)像 C++ 示例一樣正常工作:

        清單 7:Java 交換函數(shù)是否像 C++ 中那樣按引用傳遞參數(shù) class Swap
        {
        public static void main(String args[])
        {
        Integer a, b;

        a = new Integer(10);
        b = new Integer(50);

        System.out.println("before swap...");
        System.out.println("a is " + a);
        System.out.println("b is " + b);
        swap(a, b);
        System.out.println("after swap...");
        System.out.println("a is " + a);
        System.out.println("b is " + b);
        }

        public static void swap(Integer a, Integer b)
        {
        Integer temp = a;
        a = b;
        b = temp;
        }
        }



        因?yàn)?Java 應(yīng)用程序按值傳遞所有參數(shù),所以這段代碼不會(huì)正常工作,其生成的輸入如下所示:

        清單 8:清單 7 的輸出 before swap...
        a is 10
        b is 50
        after swap...
        a is 10
        b is 50



        那么,在 Java 應(yīng)用程序中如何編寫(xiě)一個(gè)方法來(lái)交換兩個(gè)基本類(lèi)型的值或兩個(gè)對(duì)象引用的值呢?因?yàn)?Java 應(yīng)用程序按值傳遞所有的參數(shù),所以您不能這樣做。要交換值,您必須用在方法調(diào)用外部用內(nèi)聯(lián)來(lái)完成。

        結(jié)論
        我在書(shū)中包括該信息的意圖并不是作瑣細(xì)的分析或試圖使問(wèn)題復(fù)雜化,而是想警告程序員:在 Java 應(yīng)用程序中假定“按引用傳遞”語(yǔ)義是危險(xiǎn)的。如果您在 Java 應(yīng)用程序中假定“按引用傳遞”語(yǔ)義,您就可能寫(xiě)出類(lèi)似上面的交換方法,然后疑惑它為什么不正常工作。

        我必須承認(rèn),在我第一次認(rèn)識(shí)到 Java 應(yīng)用程序按值傳遞所有參數(shù)時(shí),我也曾表示懷疑。我曾一直假定因?yàn)?Java 應(yīng)用程序有兩種類(lèi)型,所以他們按值傳遞基本類(lèi)型而按引用傳遞引用,就像 C++ 那樣。在轉(zhuǎn)向 Java 編程之前我已用 C++ 編程好幾年了,感覺(jué)任何其他事情似乎都不直觀(guān)。但是,一旦我理解了發(fā)生的事情,我就相信 Java 語(yǔ)言按值傳遞所有參數(shù)的方法更加直觀(guān)。The Java Programming Language,Second Edition 的作者,Ken Arnold 和 James Gosling 在 2.6.1 節(jié)中說(shuō)得最好:“在 Java 中只有一種參數(shù)傳遞模式 -- 按值傳遞 -- 這有助于使事情保持簡(jiǎn)單。”

        溫馨提示:喜歡本站的話(huà),請(qǐng)收藏一下本站!

        本類(lèi)教程下載

        系統(tǒng)下載排行

        主站蜘蛛池模板: 亚洲精品无码永久在线观看你懂的| 青娱乐免费视频在线观看| 特级淫片国产免费高清视频| 亚洲第一永久在线观看| 免费在线黄色网址| 在线aⅴ亚洲中文字幕| 青草草在线视频永久免费| 亚洲av无码专区国产不乱码 | 毛片a级毛片免费播放100| 亚洲国产成人久久77| 在线观看成人免费视频不卡| 亚洲一区二区三区乱码在线欧洲| 91视频国产免费| 亚洲国产日韩a在线播放| 免费一区二区视频| 久久久久免费视频| 亚洲国产AV无码专区亚洲AV| 国产免费拔擦拔擦8X高清在线人| 亚洲国产美国国产综合一区二区| 足恋玩丝袜脚视频免费网站| 亚洲AV日韩综合一区尤物| 在线日韩av永久免费观看| 黄色a级片免费看| 亚洲伊人色欲综合网| 5555在线播放免费播放| 亚洲一级特黄特黄的大片| 国产免费一区二区三区VR| 国产99视频精品免费视频76| 亚洲AV无码精品色午夜果冻不卡| 99视频在线精品免费| 亚洲欧美国产国产一区二区三区| 免费人成视频x8x8入口| 国内精品一级毛片免费看| 亚洲H在线播放在线观看H| 免费午夜爽爽爽WWW视频十八禁| 伊人免费在线观看高清版| 亚洲免费视频网址| 免费成人在线观看| 69国产精品视频免费| 丰满亚洲大尺度无码无码专线| 亚洲精品午夜无码电影网|