其实不论是Java中的8中基本数据类型通过直接复制值的方式传递,还是其他类型(包括自定义类型)通过所谓的引用传递,都是通过传递一个值,就是一个类型的拷贝(基本类型为直接复制值,引用方式通过复制地址的值)。
package cn.edu.nwsuaf.cie.qhs; /** * * @author 静寞小森(沧海森林) * */ public class ArgumentPassing { /** * 此处,我们将通过程序进行分析Java中参数传递的几种常见情况、问题 * 通过以常见的swap(*,*)方法为例进行阐明 * 1.以swap()为例说明大家可能都比较头痛的全局变量的情况 * 2.以swap(int,int)为例说明网上经常谈到的通过传值方式传参的情况 * 3.以swap(class,class)为例说明网上经常谈到的通过传递引用传参的情况 * 这里将class分为两种情况讨论,为了便于编程,分别采用了String类型和本类的自定义类型 * 3.1 swap(String,String) * 3.2 swap(ArgumentPassing,ArgumentPassing) * 4.以swap(int[],int pos1,int pos2)数组类型为例说明经常会误解的数组传参的情况 * 5.以实现Cloneable接口为例说明如何在对象传递时,只是传递其中的值 */ private int num1 = 1; private int num2 = 2; public int getNum1() { return num1; } public void setNum1(int num1) { this.num1 = num1; } public int getNum2() { return num2; } public void setNum2(int num2) { this.num2 = num2; } /** * 下面为使用全局变量情况的swap() */ public void swap(){ int temp = this.getNum1(); this.setNum1(this.getNum2()); this.setNum2(temp); } /** * 下面为以int为例传值传参情况的swap(int,int) */ public void swap(int num1, int num2){ int temp = num1; num1 = num2; num2 = temp; } /** * 下面为以String类型为例传引用传参情况的swap(String,String) */ public void swap(String str1,String str2){ String tempStr = str1; str1 = str2; str2 = tempStr; } /** * 下面为以ArgumentPassing自定义类型为例传引用传参情况的swap(ArgumentPassing,ArgumentPassing) */ public void swap(ArgumentPassing arg1,ArgumentPassing arg2){ int num1 = arg1.getNum1(); arg1.setNum1(arg2.getNum2()); arg2.setNum2(num1); } /** * 下面为以int[]数组类型为例传递参数情况的swap(int[],int pos1,int pos2) */ public void swap(int[] array,int pos1,int pos2){ int temp = array[pos1]; array[pos1] = array[pos2]; array[pos2] = temp; } public String toString(){ return "This object contains paramaters such as below: num1 = "+ this.getNum1()+";num2="+this.getNum2(); } public void test(){ ArgumentPassing argPassing = new ArgumentPassing(); int num1 = 1; int num2 = 2; System.out.println("调用全局变量情况下的swap()方法之前:num1="+argPassing.getNum1()+";num2="+argPassing.getNum2()); argPassing.swap(); System.out.println("调用全局变量情况下的swap()方法之后:num1="+argPassing.getNum1()+";num2="+argPassing.getNum2()); /** * 运行结果为: * 调用全局变量情况下的swap()方法之前:num1=1;num2=2 * 调用全局变量情况下的swap()方法之后:num1=2;num2=1 */ System.out.println("******************************************************************************************"); System.out.println("调用传值传参情况下的swap(int,int)方法之前:num1="+num1+";num2="+num2); argPassing.swap(num1, num2); System.out.println("调用传值传参情况下的swap(int,int)方法之后:num1="+num1+";num2="+num2); /** * 运行结果为: * 调用传值传参情况下的swap(int,int)方法之前:num1=1;num2=2 * 调用传值传参情况下的swap(int,int)方法之前:num1=1;num2=2 */ /** * 这里为什么会是这样的结果呢? * 原因就在于其为传值传递,只是负责把num1,num2的值传递给参数列表中的对应位置,复制一个值给它,然后就和他们没有关系了。 * 所以即使是在函数体内,其对应的参数列表的参数值改变了,也和它(们)没有关系了。 */ System.out.println("******************************************************************************************"); String str1 = "This is str1"; String str2 = "This is Str2"; System.out.println("调用传递引用传参情况下的swap(String,String)方法之前:str1="+str1+";str2="+str2); argPassing.swap(str1, str2); System.out.println("调用传递引用传参情况下的swap(String,String)方法之后:str1="+str1+";str2="+str2); /** * 运行结果为: * 调用传递引用传参情况下的swap(String,String)方法之前:str1=This is str1;str2=This is Str2 * 调用传递引用传参情况下的swap(String,String)方法之后:str1=This is str1;str2=This is Str2 */ /** * 为什么呢?为什么结果却是这样子的?我们不是通过传递引用传递过来的吗?如果你是C++的程序猿或者对C++有着一定的了解,你一定纳闷, * C++里引用这样就是可以的,可以交换的呀!为什么这里却是这样子的呢?不要着急,看下面的另一个通过引用来交换的例子。 */ System.out.println("******************************************************************************************"); ArgumentPassing arg1 = new ArgumentPassing(); ArgumentPassing arg2 = new ArgumentPassing(); System.out.println("调用传递引用传参情况下的swap(ArgumentPassing,ArgumentPassing)方法之前:arg1="+arg1.toString()+";arg2="+arg2.toString()); argPassing.swap(arg1, arg2); System.out.println("调用传递引用传参情况下的swap(ArgumentPassing,ArgumentPassing)方法之后:arg1="+arg1.toString()+";arg2="+arg2.toString()); /** * 运行结果为: * 调用传递引用传参情况下的swap(ArgumentPassing,ArgumentPassing)方法之前:arg1=This object contains paramaters such as below: num1 = 1;num2=2;arg2=This object contains paramaters such as below: num1 = 1;num2=2 *调用传递引用传参情况下的swap(ArgumentPassing,ArgumentPassing)方法之后:arg1=This object contains paramaters such as below: num1 = 2;num2=2;arg2=This object contains paramaters such as below: num1 = 1;num2=1 */ /** * 为什么结果是这样子的呢?为什么和上面的结果完全不一样呢?当然很好解释了。 * 因为Java中虽然是通过引用传递的,但是是传递的引用的副本(即将保存这个数据的地址复制了一份给参数(列表)), * 然后如果只是像上面的swap(String,String)那样子交换的话,其实是改变了其参数列表中参数的指向(指针指向),却无法改变外边变量的值。 * 然后下面的这种就是讲参数列表中指向的地址中的内容进行了改变,如果没有改变的地方,很明显是没有变化的。 * 也就是说其实Java中的所谓的传递引用传递,其实根本就是传递了一份地址的值的拷贝,然后也可以说成是值传递。 */ System.out.println("******************************************************************************************"); int [] array = {1,2,3,4}; int pos1 = 0; int pos2 = 1; System.out.println("调用数组传参情况下的swap(int[],int pos1,int pos2)方法之前:array[pos1]="+array[pos1]+";array[pos2]="+array[pos2]); argPassing.swap(array, pos1, pos2); System.out.println("调用数组传参情况下的swap(int[],int pos1,int pos2)方法之后:array[pos1]="+array[pos1]+";array[pos2]="+array[pos2]); /** * 运行结果为: * 调用数组传参情况下的swap(int[],int pos1,int pos2)方法之前:array[pos1]=1;array[pos2]=2 * 调用数组传参情况下的swap(int[],int pos1,int pos2)方法之后:array[pos1]=2;array[pos2]=1 */ /** * 这里的原因,有了上面所阐述的swap(ArgumentPassing,ArgumentPassing)结果的原因,以后就比较好理解了吧。其实数组传递,就是传递的数组的首地址的值, * 然后传递了两个位置,就是将数组中的内容进行改变,这样一来,就是将指定地址中的内容值改变了,外边的数组参数内容自然就改变了。 */ /** * 大家可能比较纳闷,为什么还要说一说实现Cloneable接口呢?其实道理也是很简单的,因为有的时候,一个自定义类中包含另一个自定义类的对象,所以有时候我们不需要 * 改变对象中本来的值,只是拿来用一下,然后在其他地方改变或是修改什么的,这时候,要是直接使用=,就不是上策了,当然Java中也为我们想好了,这就是实现Cloneable接口。 * 其中只有一个方法clone,进行重写就可以了。 * 就不在详细说明了,只是提醒一下大家有这么个方式,遇到这类的问题,可以这么解决,有了这个方向,就很好找到这一类的资料,网上多的很呢。 */ } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub ArgumentPassing argPassing = new ArgumentPassing(); argPassing.test(); } }