溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java應(yīng)用程序中的按值傳遞語義是什么

發(fā)布時間:2022-01-06 21:05:16 來源:億速云 閱讀:120 作者:柒染 欄目:編程語言

這篇文章給大家介紹Java應(yīng)用程序中的按值傳遞語義是什么,內(nèi)容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

Java 應(yīng)用程序中的按值傳遞語義 

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

對此節(jié)選的某些反饋意見認為,我把這一問題搞糊涂了,或者將它完全搞錯了。在此欄目中我將使用 C++ 和 Java 應(yīng)用程序進一步闡明一些事實。

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

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

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

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

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

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

清單 1:C++ 示例

#include#includevoid 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 %dn", val); printf("pint is %dn", pint); printf("*pint is %dn", *pint); printf("ref is %dnn", ref); printf("calling modifyn"); //按值傳遞 val 和 pint,按引用傳遞 ref。 modify(val, pint, ref); printf("returned from modifynn"); printf("val is %dn", val); printf("pint is %dn", pint); printf("*pint is %dn", *pint); printf("ref is %dn", 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 %dn", a); printf("p is %dn", p); printf("r is %dn", 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


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

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

  • 將第一個參數(shù)設(shè)置為 0。

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

  • 將第三個參數(shù)設(shè)置為 0。

將新值打印出來,然后函數(shù)返回。當(dāng)執(zhí)行返回到 main 時,再次打印出這三個參數(shù)的值以及指針?biāo)赶虻闹怠W鳛榈谝粋€和第二個參數(shù)傳遞的變量不受 modify 函數(shù)的影響,因為它們是按值傳遞的。但指針?biāo)赶虻闹蹈淖兞?。請注意,與前兩個參數(shù)不同,作為最后一個參數(shù)傳遞的變量被 modify 函數(shù)改變了,因為它是按引用傳遞的。

現(xiàn)在考慮用 Java 語言編寫的類似代碼:

清單 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


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

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

  • 將第一個參數(shù)(整數(shù))設(shè)置為 0。

  • 將第一個對象引用 r1 設(shè)置為 null。

  • 保留第二個引用 r2 的值,但通過調(diào)用 append 方法更改它所引用的對象(這與前面的 C++ 示例中對指針 p 的處理類似)。

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

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

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

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

#include#includevoid 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ù)類似以下代碼,其中引用是按引用傳遞的:

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

#include#includevoid 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; }


兩個 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; } }


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

清單 8:清單 7 的輸出

before swap... a is 10 b is 50 after swap... a is 10 b is 50

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

關(guān)于Java應(yīng)用程序中的按值傳遞語義是什么就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI