Java语言提供了两种参数传递的方式:值传递和引用传递。
值传递: 在方法调用中,实参会把它的值传递给形参,形参只是用实参的值初始化一个临时的储存单元,因此形参和实参虽然有着形同的值,但是却有着不同的地址单元,因此对形参的改变不会影响实参的值。
引用传递: 在方法调用中,传递的是对象,这时形参和实参的对象指向同一块储存单元,因此对形参的修改就会影响实参的值。
首先,我们先考虑基本数据类型。
一个常见的交换手段:
public static void main(String[] args) {
int a = 10;
int b = 20;
swap(a,b);
System.out.println(a);
System.out.println(b);
}
private static void swap(int a, int b) {
int tmp = a;
a = b;
b = a;
}
结果如下:
显然,交换失败。由于a和b都是基本数据类型,所以参数是按值传递的,其形参的改变不会实参的值。在c里面可以用指针传地址的方法在外函数让局部变量的基本数据类型进行交换,由于Java里面没有指针(为了安全性,无法获得变量的地址)所以无法在外函数让局部变量的基本数据类型进行交换,但是可以使用类似指针的引用传递让成员的基本数据类型在外函数内进行交换。
public class Solution {
int a = 10;
int b = 20;
public static void main(String[] args) {
Solution s = new Solution();
swap(s);
System.out.println(s.a);
System.out.println(s.b);
}
private static void swap(Solution s) {
int tmp = s.a;
s.a = s.b;
s.b = tmp;
}
}
结果如下:
再讨论引用数据类型。
先看一个相对而言比较特殊的引用类型,数组。
public static void main(String[] args) {
int[] arr = new int[2];
for (int i = 0; i < 2; i++) {
arr[i] = i;
}
System.out.println(Arrays.toString(arr));
swap(arr[0],arr[1]);//值传递
System.out.println(Arrays.toString(arr));
swap1(arr);//引用传递
System.out.println(Arrays.toString(arr));
}
private static void swap(int a, int b) {
int tmp = a;
a = b;
b = tmp;
}
private static void swap1(int[] arr) {
int tmp = arr[0];
arr[0] = arr[1];
arr[1] = tmp;
}
结果如下:
显然,第一个交换失败,第二个交换成功,至于原因和上述的交换原理一样。
再看一个字符串的例子。
public class Solution {
String name = "java";
public static void main(String[] args) {
Solution s = new Solution();
change(s.name);
System.out.println(s.name);
change1(s);
System.out.println(s.name);
}
private static void change(String name) {
name = "c++";
}
private static void change1(Solution s) {
s.name = "c++";
}
}
结果如下:
虽然两种方式都是引用传递,两个形参传的都是对象,但是其实引用也是按值传递的。
第一种方式只不过是新产生了一个“C++”的对象,但是最终name对象还是指向了“java”。
但是第二种方式通过传入类的实例化对象,使得成员变量name指向“C++”而改变的结果。
最后再看一个StringBuffer的例子。
public class Solution {
StringBuffer s1 = new StringBuffer("Hello");
StringBuffer s2 = new StringBuffer("Hello");
public static void main(String[] args) {
Solution s = new Solution();
change(s.s1,s.s2);
System.out.println(s.s1);
System.out.println(s.s2);
change1(s);
System.out.println(s.s1);
System.out.println(s.s2);
}
private static void change(StringBuffer s1,StringBuffer s2) {
s1.append("Java");
s2 = s1;
}
private static void change1(Solution s) {
s.s1.append("Java");
s.s2 = s.s1;
}
}
结果如下:
基本原理和上述String的例子大同小异,只不过这里的append()方法会修改形参里面所指向字符串的值,所以使得最终的结果会发生变化,这种方式类似于上述的第二种数组交换方式。