關于 Java 應用程序中參數傳遞的某些混淆源于這樣一個事實:許多程序員都是從 C++ 編程轉向 Java 編程的。C++ 既包含非引用類型,又包含引用類型,并分別按值和按引用傳遞它們。Java 編程語言有基本類型和對象引用;因此,認為 Java 應用程序像 C++ 那樣對基本類型使用按值傳遞,而對引用使用按引用傳遞是符合邏輯的。究竟您會這么想,假如正在傳遞一個引用,則它一定是按引用傳遞的。很輕易就會相信這一點,實際上有一段時間我也相信是這樣,但這不正確。
在 C++ 和 Java 應用程序中,當傳遞給函數的參數不是引用時,傳遞的都是該值的一個副本(按值傳遞)。區別在于引用。在 C++ 中當傳遞給函數的參數是引用時,您傳遞的就是這個引用,或者內存地址(按引用傳遞)。在 Java 應用程序中,當對象引用是傳遞給方法的一個參數時,您傳遞的是該引用的一個副本(按值傳遞),而不是引用本身。請注重,調用方法的對象引用和副本都指向同一個對象。這是一個重要區別。Java 應用程序在傳遞不同類型的參數時,其作法與 C++ 并無不同。Java 應用程序按值傳遞所有參數,這樣就制作所有參數的副本,而不管它們的類型。
示例 我們將使用前面的定義和討論分析一些示例。首先考慮一段 C++ 代碼。C++ 語言同時使用按值傳遞和按引用傳遞的參數傳遞機制:
清單 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; 這段代碼的輸出為:
清單 2:C++ 代碼的輸出
val is 10pint is 4262128*pint is 15ref is 50calling modifyin modify...a is 0p is 0r is 0returned from modifyval is 10pint is 4262128*pint is 7ref is 0
將新值打印出來,然后函數返回。當執行返回到 main 時,再次打印出這三個參數的值以及指針所指向的值。作為第一個和第二個參數傳遞的變量不受 modify 函數的影響,因為它們是按值傳遞的。但指針所指向的值改變了。請注重,與前兩個參數不同,作為最后一個參數傳遞的變量被 modify 函數改變了,因為它是按引用傳遞的。
現在考慮用 Java 語言編寫的類似代碼:
清單 3:Java 應用程序
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"); //按值傳遞所有參數 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 應用程序的輸出
val is 10sb1 is applessb2 is pearscalling modifyin modify...a is 0r1 is nullr2 is pears taste goodreturned from modifyval is 10sb1 is applessb2 is pears taste good
編寫一個交換方法 假定我們知道參數是如何傳遞的,在 C++ 中編寫一個交換函數可以用不同的方式完成。使用指針的交換函數類似以下代碼,其中指針是按值傳遞的:
清單 5:使用指針的交換函數
#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;}
使用引用的交換函數類似以下代碼,其中引用是按引用傳遞的:
清單 6:使用引用的交換函數
#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;}
兩個 C++ 代碼示例都像所希望的那樣交換了值。假如 Java 應用程序使用“按引用傳遞”,則下面的交換方法應像 C++ 示例一樣正常工作:
清單 7:Java 交換函數是否像 C++ 中那樣按引用傳遞參數
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