关于 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; 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 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