首先解释解释一下,关于Java参数传递的一些个人看法。
其实不论是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();
}
}