JAVA中的参数传递

    JAVA的许多教材中提到:java中没有引用传递,只有值传递。因此为了实现C++等语言中的引用,JAVA中提供了如下的引用类型:数组、类(包括对象)、接口、枚举。 
    但许多朋友却遇到这样的问题:在交换两个数的程序中,用JAVA中的类来进行参数传递同样无法交换两个变量的值,好像还是值传递,而不是引用传递。           
    下面首先引入一段程序:Code1:
public class Test
{
public int data;
public Test(int data){this.data = data;}

public static void swap(Test a, Test b)
{Test tmp= a;a = b;b = tmp;}

public static void main(String[] args)
{ Test ta=new Test(2); Test tb=new Test(5);
 Test.swap(ta, tb);
System.out.println("ta.data="+ta.data+"\t"+"tb.data="+tb.data);
}
}

 

     
本程序的输出结果是:ta.data=2        tb.data=5
   很多朋友郁闷,swap()函数也传递的是类,按照正常的经验,输出应该是:a.data=5       b.data=2 才是,可结果却令人大跌眼镜。其实教材上并没有问题,机器运行的结果永远是最好的证明,还是我们对引用传递的机制理解的太浅显所致。
   本程序中swap()函数传递的是Test类型,但其实实现的还是按值传递的机制。这可以和C语言类比,C中也没有真正的引用传递,只有值传递,只是借助指针间接地实现了引用传递。这里首先说明C语言中的一个指针的例子:int a=20;int *p=&a;这里p是一个指针型变量,a的内容是一个int型的值20,p的内容是一个指针(a变量的的地址3F60),这样就可以用*p访问a了(若单从访问20这个数来看,用指针访问时系统似乎另外分配了一个存放地址的单元,不同编译器对此分配不同的单元,Turbo C++中指针变量本身占用2个字节,VC++中指针变量本身占用4个字节的存储空间。有关指针的详细知识请参考相关资料)。
 
   在C语言中,定义 void swap(int *a,int *b){int temp; temp=*a;  *a=*b;   *b=temp;}    这样的函数,调用swap(&a,&b)来实现引用传递,从而成功交换两个变量的值。
   再来说上述的JAVA程序,JAVA中的类、对象、数组什么的在当做参数时可以看做是C、C++中的地址(或指针)。虽然 public static void swap(Test a, Test b)的参数是Test类,但在函数体内其实也只是对指针变量内容的交换(即还是指针变量内容的直接交换),而不是指针变量指向的单元内容的交换(注意:JAVA中没有指针的概念,此处只是为了理解暂且这么说)。这里的Test a相当于上述C语言中的指针变量p,通过public static void swap(Test a, Test b)函数只是改变了p的内容(即p内容中的3F60),但当函数条用完毕后,局部变量自动撤销,故ta和tb的指向还是本身,其data值也没有变。其实指针变量也是一种变量类型,与int、double一样,上述就可以看做是两个int型的变量,这样就很容易看出是值传递而不是引用传递。而上面的C语言函数void swap(int *a,int *b)    {int temp;     temp=*a;    *a=*b;     *b=temp;}    却是改变的是*p的内容(即p指向的3F60单元的值20),而调用时swap(&a,&b)传递的是a,b的地址,故当调用结束是a,b的地址未变(如a的地址还是3F60),变化的是a,b存储单元的内容的值,从而使两个变量的交换。读者请仔细分析其中的差别,理解上述程序的错误所在。
 
   同样以下的程序结果也可用上述的说明来解释:由于StringBuffer是系统类,但y=x知识改变y的内容,而不是改变其指向的单元的内容;而x.append(y)却x的地址不变而其指向的单元内容改变(读者可查看StringBuffer与String的不同)。Code2:
 
public class Test {
    public static void main(String [ ] args) {
        StringBuffer a = new StringBuffer("A");
        StringBuffer b = new StringBuffer("B");
        change(a , b);
        System.out.println(a + "," + b);
    }
    static void change(StringBuffer x , StringBuffer y) {
        x.append(y);
        y = x;
    }
}

 

结果显示:  AB , B

 

下面给出JAVA中的两个变量的其他交换示例,来说明JAVA中的值传递与引用传递的机制。

public class SwapNumbers {   
    public int a;   
    public int b;   
       
    public SwapNumbers(int a,int b){
    	this.a=a;  this.b=b;
    }
    
    //包装类交换   
    public static void swap (Integer a, Integer b) {       
        Integer temp = a;   
        a = b;   
        b = temp;   
    };   
       
    //直接交换   
    public static void swap (int a, int b) {       
        int temp = a;   
        a = b;   
        b = temp;   
    };   
       
    //对象成员交换  
    public static void swap (SwapNumbers a,SwapNumbers b) {       
        int tempa = a.a,tempb=a.b;   
        a.a =b.a;  a.b=b.b; 
        b.a = tempa;  b.b=tempb; 
    }; 
    
    //数组   
    public static void swap (int[] arr) {      
        int temp = arr[0];   
        arr[0] = arr[1];   
        arr[1] = temp;   
    };   
       
    //类本身内交换  
    public  void swapNum(int a, int b) {       
        this.a = b;   
        this.b = a;   
    };   
       
    //包装类打印   
    public static void print(Integer m, Integer n) {   
        System.out.println("m=" + m.intValue() + " n=" + n.intValue());   
    }   
    //直接打印   
    public static void print(int a, int b) {   
        System.out.println("a=" + a + " b=" + b);   
    }   
    //对象打印   
    public static void print(SwapNumbers a,SwapNumbers b) {   
        System.out.println("a.a=" + a.a + "  a.b=" + a.b+"\t"+"b.a=" + b.a + "  b.b=" + b.b);   
    }   
    //数组打印   
    public static void print(int[] a) {   
        for (int i : a) {   
            System.out.print(i + " ");   
        }   
        System.out.println();   
    }   
    //类本身打印
    public void print() {   
        System.out.println("a=" + this.a + " b=" + this.b);   
    } 
       
    public static void main(String[] args) {   
                           
        System.out.println("------包装类交换--------");   
        Integer m = new Integer(2);   
        Integer n = new Integer(3);        
             
        print(m,n);   
        swap(m, n);   
        print(m,n);  
        
        System.out.println("------直接交换----------");   
        int a = 2, b = 3;   
           
        print(a,b);   
        swap(a, b);   
        print(a,b);   
        
        System.out.println("-----对象成员交换-------");   
        SwapNumbers oa = new SwapNumbers(2,3); 
        SwapNumbers ob = new SwapNumbers(4,5);
           
        print(oa,ob);   
        swap(oa, ob);   
        print(oa,ob);   
           
        System.out.println("-------数组交换---------");   
        int[] arr = {2,3};   
        print(arr);   
        swap(arr);   
        print(arr);   
           
        System.out.println("-----类本身内交换-------");   
        print(a,b);   
        SwapNumbers sn = new SwapNumbers(2,3);   
        sn.swapNum(a, b);   
        sn.print();   
           
    }   
} 


输出结果:

 

 

------包装类交换--------
m=2n=3
m=2n=3
------直接交换----------
a=2b=3
a=2b=3
-----对象成员交换-------
a.a=2 a.b=3   b.a=4  b.b=5
a.a=4 a.b=5   b.a=2  b.b=3
-------数组交换---------
23 
32 
-----类本身内交换-------
a=2b=3
a=3b=2

 

 

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章