参数传递解析(转贴)

 
JavaC++中的参数传递
  
1概念定义
 
1.1按值传递:
将一个参数传递给一个函数时,函数接收的是原始值的一个副本。因此,如果函数修改了该参数,仅改变副本,而原始值保持不变。
 
1.2按引用传递:
 
将一个参数传递给一个函数时,函数接收的是原始值的内存地址,不是值的副本。因此,如果函数修改了该参数指向的内容,调用代码中的原始值也随之改变。
 
2 C++和Java应用程序中的参数传递
    C++和Java中,当参数不是引用时,传递的都是该值的一个副本(按值传递)。
区别在于引用
在C++中参数是引用时,您传递的就是这个引用,或者内存地址(按引用传递)。
在Java中参数是对象引用时,您传递的是该引用的一个副本(按值传递),而不是引用本身,但是调用方法的对象引用和副本都指向同一个对象。
总之,Java应用程序在传递不同类型的参数时,其作法与C++并无不同。Java应用程序按值传递所有参数,这样就制作所有参数的副本,而不管它们的类型。
 
3 实例解析
 
3.1代码一(C++版本)
 
#include<iostream></iostream> 
using namespace std;
 
void modify(int a, int *p, int &r)
{
    printf("in modify...\n");
    a = 0;
    *p = 7;
    p = 0;
    r = 0;
    printf("a is %d\n", a);
    printf("p is %d\n", p);
    printf("r is %d\n", r);
}
 
int main ()
{
 int val, ref;
 int *pint;
 
 val = 10;
 ref = 50;
 pint = (int*)malloc(sizeof(int));
 *pint = 15;
 
 printf("val is %d\n", val);
 printf("pint is %d\n", pint);
 printf("*pint is %d\n", *pint);
 printf("ref is %d\n\n", ref);
 
 printf("calling modify\n");
  
 modify(val, pint, ref);
 printf("returned from modify\n\n");
 
 printf("val is %d\n", val);
 printf("pint is %d\n", pint);
 printf("*pint is %d\n", *pint);
 printf("ref is %d\n", ref);
 
 return 0;
}
程序运行结果:
val is 10
pint is 4262128
*pint is 15
ref is 50
 
calling modify
in modify...
a is 0
p is 0
r is 0
returned from modify
 
val is 10
pint is 4262128
*pint is 7
ref is 0
 
这段代码声明了三个变量:两个整型变量和一个指针变量。将所有三个变量作为参数传递给modify()。前两个参数是按值传递的,最后一个参数是按引用传递的。
Modify()的函数原型表明最后一个参数要作为引用传递。C++按值传递所有参数,引用除外;
Modify()更改了所有三个参数的值:
将第一个参数设置为0。
将第二个参数所指向的值设置为7,然后将第二个参数设置为0。
将第三个参数设置为0。
将新值打印出来,然后函数返回。
当执行返回到main时,再次打印出这三个参数的值以及指针所指向的值。
第一个和第二个参数由于按值传递,所以实参不受modify函数的影响。但指针所指向的值改变了。最后一个参数由于按引用传递,所以实参被modify函数改变了。
 
 
3.2代码二(Java版本)
 
class Test
{
    public static void modify( int a, StringBuffer r1, StringBuffer r2)
    {
        System. out .println( "in modify..." );
        a = 0;
        r1 = null ; //1
        r2.append( " taste good" );
        System. out .println( "a is " + a);
        System. out .println( "r1 is " + r1);
        System. out .println( "r2 is " + r2);
    }
 
    public static void main(String args[])
    {
        int val;
        StringBuffer sb1, sb2;
 
        val = 10;
        sb1 = new StringBuffer( "apples" );
        sb2 = new StringBuffer( "pears" );
        System. out .println( "val is " + val);
        System. out .println( "sb1 is " + sb1);
        System. out .println( "sb2 is " + sb2);
        System. out .println();
 
        System. out .println( "calling modify" );
        // 按值传递所有参数
        modify(val, sb1, sb2);
        System. out .println( "returned from modify" );
        System. out .println( "" );
 
        System. out .println( "val is " + val);
        System. out .println( "sb1 is " + sb1);
        System. out .println( "sb2 is " + sb2);
    }
}
 
运行结果:
val is 10
sb1 is apples
sb2 is pears
 
calling modify
in modify...
a is 0
r1 is null
r2 is pears taste good
returned from modify
 
val is 10
sb1 is apples
sb2 is pears taste good
代码声明了三个变量:一个整型变量和两个对象引用。将所有三个变量作为参数传递给modify()。
Modify()更改了所有三个参数的值:
将第一个参数(整数)设置为0。
将第一个对象引用r1设置为null。
保留第二个引用r2的值,但调用append()更改它所引用的对象
返回到main()时,整型的val没有改变。对象引用sb1也没有改变。
如果sb1是按引用传递的,正如许多人声称的那样,它将为null但是,因为Java中按值传递所有参数,所以是sb1的引用的一个副本传递给了modify()方法。
当modify()中将r1设置为null时,它只是对sb1的引用的一个副本进行了该操作,而不是像C++中那样对原始值进行操作。
第二个对象引用sb2打印出的是在modify()中设置的新字符串。是因为modify()中的引用副本和sb2指向同一个对象,所以对复制的引用所调用的方法更改的是同一个对象。
 
 
3.3经典的交换函数
 
3.3.1利用指针来实现
 
 void swap(int *a, int *b)
{
 int temp = *b;
 *b = *a;
 *a = temp;
}
 
int main (int argc, char** argv)
{
 int val1, val2;
 val1 = 10;
 val2 = 50;
 swap(&val1, &val2);
 return 0;
}
 
3.3.2利用引用来实现
 
 void swap(int &a, int &b)
{
 int temp = b;
 b = a;
 a = temp;
}
 
int main (int argc, char** argv)
{
 int val1, val2;
 val1 = 10;
 val2 = 50;
 swap(val1, val2);
 return 0;
}
 
 
3.3.3 Java利用引用来实现
 
  class Swap
{
    public static void swap(Integer a, Integer b)
    {
        Integer temp = a;
        a = b;
        b = temp;
    }
   
    public static void main(String args[])
    {
        Integer a, b;
 
        a = new Integer(10);
        b = new Integer(50);
 
        System. out .println( "before swap..." );
        System. out .println( "a is " + a);
        System. out .println( "b is " + b);
        swap(a, b);
        System. out .println( "after swap..." );
        System. out .println( "a is " + a);
        System. out .println( "b is " + b);
    }
}
 
运行结果:
before swap...
a is 10
b is 50
after swap...
a is 10
b is 50
Java中的函数参数传值是按值传值!
 
 
3.4 Java版本的综合实例
 
  class MyInteger
{
    private int     inner ;
   
    public MyInteger( int inner)
    {
        this . inner = inner;
    }
   
    public void setInt( int i)
        {
            inner = i;
        }
 
        public int getInt()
        {
            return inner ;
        }
 
        public String toString()
        {
            return "" + inner ;
        }
    }
 
class Swap
{
    public static void swap(MyInteger a, MyInteger b)
    {
        pl( "swap" );
        MyInteger temp = a;
        a = b;
        b = temp;
    }
 
    public static void swapI(MyInteger a, MyInteger b)
    {
        pl( "swapI" );
        MyInteger temp = a;
        a = new MyInteger(b.getInt());
        b = new MyInteger(temp.getInt());
    }
 
    public static void swapII(MyInteger a, MyInteger b)
    {
        pl( "swapII" );
        int temp = a.getInt();
        a.setInt(b.getInt());
        b.setInt(temp);
    }
   
    public static void main(String[] args)
    {
        MyInteger a = new MyInteger(1);
        MyInteger b = new MyInteger(2);
        pl(a);
        pl(b);
        swap(a, b);
        pl(a);
        pl(b);
        swapI(a, b);
        pl(a);
        pl(b);
        swapII(a, b);
        pl(a);
        pl(b);
    }
 
    private static void pl(Object a)
    {
        System. out .println(a);
    }
}
 
运行结果:
1
2
Swap //交换的是实参的引用副本,所以对原来的调用函数没什么影响
1
2
swapI //操作的是实参的引用副本
1
2
swapII //操作的是引用副本所指向的内容,所以对调用函数会发生变化
2
1
 
总之,在函数参数传递的过程当中Java自动调用Object::clone(),想要进行深拷贝的调用,自己要显示的指明!
public static void swap(MyInteger i, MyInteger j)
{
    i.setValue(40);
    j.setValue(50);
}
swap ((MyInteger)a.clone(),(MyInteger)b.clone());
 
 
3.5 思考下面的例子
 
 package hziee; 
 
public class StringTest
{
    static void func(String s)
    {
        s += "tail" ;
    }
 
    static void test()
    {
        String a = "abc" ;
        func(a);
        System. out .println(a);
    }
 
    public static void main(String[] args)
    {
        test();
    }
}
 
看了上面的介绍内容应该明白是什么原因了吧?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值