Java中没有引用传递只有值传递(在函数中)
◆传参的问题
引用类型(在函数调用中)的传参问题,是一个相当扯的问题。有些书上说是传值,有些书上说是传引用。搞得Java程序员都快成神经分裂了。所以,我们最后来谈一下“引用类型参数传递”的问题。
如下例子,假设现在要把刚才创建的那一坨字符串打印出来,我们会使用如下语句:
StringBuffer str = new StringBuffer(); System.out.println(str); //这个语句又是什么意思捏?这时候就两说了。
第一种理解:可以认为传进函数的是str这个指针,指针说白了就是一个地址的值,说得再白一点,就是个整数。按照这种理解,就是传值的方式。也就是说,参数传递的是指针本身,所以是传值的。
第二种理解:可以认为传进去的是StringBuffer对象,按照这种理解,就是传引用方式了。因为我们确实是把对象的地址(也就是引用)给传了进去。
费了这么多口水,其实不论是传引用还是传值,都可以讲得通,关键取决于你是如何看待参数所传递的东西。这就好比量子力学中“光的波粒二象性”,如果你以粒子的方式去测量它,它看起来像粒子;如果你以波动的方式去观测它,它看起来像波动。
/** * @description Java中没有引用传递只有值传递 * * @author Alexia * @date 2013-10-16 * */ class Person { private String name; private String sex; public Person(String x, String y) { this.name = x; this.sex = y; } // 重写toString()方法,方便输出 public String toString() { return name + " " + sex; } // 交换对象引用,这里的p1和p2是swapObject这个函数的变量(局部变量), // p1、p2接收的就是传递进来的一个堆内存的地址,改变p1、p2的指向只是改变了这两个局部变量的指向。 // 实际的全局变量还是没变的 public static void swapObject(Person p1, Person p2) { Person tmp = p1; p1 = p2; p2 = tmp; } // 交换基本类型 public static void swapInt(int a, int b) { int tmp = a; a = b; b = tmp; } // 交换对象数组 public static void swapObjectArray(Person[] p1, Person[] p2) { Person[] tmp = p1; p1 = p2; p2 = tmp; } // 交换基本类型数组 public static void swapIntArray(int[] x, int[] y) { int[] tmp = x; x = y; y = tmp; } // 改变对象数组中的内容 public static void changeObjectArray(Person[] p1, Person[] p2) { Person tmp = p1[1]; p1[1] = p2[1]; p2[1] = tmp; // 再将p1[1]修改 Person p = new Person("wjl", "male"); p1[1] = p; } // 改变基本类型数组中的内容 public static void changeIntArray(int[] x, int[] y) { int tmp = x[1]; x[1] = y[1]; y[1] = tmp; x[1] = 5; } } public class ByValueTest { public static void main(String[] args) { // 建立并构造两个对象 Person p1 = new Person("Alexia", "female"); Person p2 = new Person("Edward", "male"); System.out.println("对象交换前:p1 = " + p1.toString()); //Alexia female System.out.println("对象交换前:p2 = " + p2.toString()); //Edward male // 交换p1对象和p2对象 Person.swapObject(p1, p2); // 从交换结果中看出,实际对象并未交换 System.out.println("对象交换后:p1 = " + p1.toString()); //Alexia female System.out.println("对象交换后:p2 = " + p2.toString()); //Edward male // 建立两个对象数组 Person[] arraya = new Person[2]; Person[] arrayb = new Person[2]; // 分别构造数组对象 arraya[0] = new Person("Alexia", "female"); arraya[1] = new Person("Edward", "male"); arrayb[0] = new Person("jmwang", "female"); arrayb[1] = new Person("hwu", "male"); System.out.println("对象数组交换前:arraya[0] = " + arraya[0].toString() + ", arraya[1] = "
+ arraya[1].toString()); //Alexia female,Edward male System.out.println("对象数组交换前:arrayb[0] = " + arrayb[0].toString() + ", arrayb[1] = "
+ arrayb[1].toString()); //jmwang female,hwu male // 交换这两个对象数组 Person.swapObjectArray(arraya, arrayb); System.out.println("对象数组交换后:arraya[0] = " + arraya[0].toString() + ", arraya[1] = "
+ arraya[1].toString()); //Alexia female,Edward male System.out.println("对象数组交换后:arrayb[0] = " + arrayb[0].toString() + ", arrayb[1] = "
+ arrayb[1].toString()); //jmwang female,hwu male // 建立两个普通数组 int[] a = new int[2]; int[] b = new int[2]; // 给数组个元素赋值 for (int i = 0; i < a.length; i++) { a[i] = i; b[i] = i + 1; } System.out.println("基本类型数组交换前:a[0] = " + a[0] + ", a[1] = " + a[1]); //0,1 System.out.println("基本类型数组交换前:b[0] = " + b[0] + ", b[1] = " + b[1]); //1,2 // 交换两个基本类型数组 Person.swapIntArray(a, b); System.out.println("基本类型数组交换后:a[0] = " + a[0] + ", a[1] = " + a[1]); //0,1 System.out.println("基本类型数组交换后:b[0] = " + b[0] + ", b[1] = " + b[1]); //1,2 // 改变对象数组的内容 Person.changeObjectArray(arraya, arrayb); System.out.println("对象数组内容交换并改变后:arraya[0] = " + arraya[0].toString() + ", arraya[1] = "
+ arraya[1].toString()); //Alexia female,wjl male System.out.println("对象数组内容交换并改变后:arrayb[0] = " + arrayb[0].toString() + ", arrayb[1] = "
+ arrayb[1].toString()); //jmwang female,Edward male // 改变基本类型数组的内容 Person.changeIntArray(a, b); System.out.println("基本类型数组内容交换并改变后:a[0] = " + a[0] + ", a[1] = " + a[1]); //0,5 System.out.println("基本类型数组内容交换并改变后:b[0] = " + b[0] + ",b[1] = " + b[1]); //1,1 } }
说明:不管是对象、基本类型还是对象数组、基本类型数组,在函数中都不能改变其实际地址但能改变其中的内容。
【相当于传递进来的栈内存的值,栈内存只存放地址和基本数据内容,是不可在函数中改变的】