Java和C++中的参数传递

来源:互联网 发布:罗马2全面战争mac版 编辑:程序博客网 时间:2024/06/08 08:01
 
1概念定义
 
1.1按值传递:
将一个参数传递给一个函数时,函数接收的是原始值的一个副本。因此,如果函数修改了该参数,仅改变副本,而原始值保持不变。
 
1.2按引用传递:
 
将一个参数传递给一个函数时,函数接收的是原始值的内存地址,不是值的副本。因此,如果函数修改了该参数指向的内容,调用代码中的原始值也随之改变。
 
2 C++和Java应用程序中的参数传递
   C++和Java中,当参数不是引用时,传递的都是该值的一个副本(按值传递)。
区别在于引用
在C++中参数是引用时,您传递的就是这个引用,或者内存地址(按引用传递)。
在Java中参数是对象引用时,您传递的是该引用的一个副本(按值传递),而不是引用本身,但是调用方法的对象引用和副本都指向同一个对象。
总之,Java应用程序在传递不同类型的参数时,其作法与C++并无不同。Java应用程序按值传递所有参数,这样就制作所有参数的副本,而不管它们的类型。
 
3 实例解析
 
3.1代码一(C++版本)
 
#include 
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
{
    publicstaticvoid 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);
    }
 
    publicstaticvoid 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
{
    publicstaticvoid swap(Integer a, Integer b)
    {
        Integer temp = a;
        a = b;
        b = temp;
    }
   
    publicstaticvoid 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
{
    privateint    inner;
   
    public MyInteger(int inner)
    {
        this.inner = inner;
    }
   
    publicvoid setInt(int i)
        {
            inner = i;
        }
 
        publicint getInt()
        {
            returninner;
        }
 
        public String toString()
        {
            return"" + inner;
        }
    }
 
class Swap
{
    publicstaticvoid swap(MyInteger a, MyInteger b)
    {
        pl("swap");
        MyInteger temp = a;
        a = b;
        b = temp;
    }
 
    publicstaticvoid swapI(MyInteger a, MyInteger b)
    {
        pl("swapI");
        MyInteger temp = a;
        a = new MyInteger(b.getInt());
        b = new MyInteger(temp.getInt());
    }
 
    publicstaticvoid swapII(MyInteger a, MyInteger b)
    {
        pl("swapII");
        int temp = a.getInt();
        a.setInt(b.getInt());
        b.setInt(temp);
    }
   
    publicstaticvoid 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);
    }
 
    privatestaticvoid pl(Object a)
    {
        System.out.println(a);
    }
}
 
运行结果:
1
2
Swap //交换的是实参的引用副本,所以对原来的调用函数没什么影响
1
2
swapI //操作的是实参的引用副本
1
2
swapII //操作的是引用副本所指向的内容,所以对调用函数会发生变化
2
1
 
总之,在函数参数传递的过程当中Java自动调用Object::clone(),想要进行深拷贝的调用,自己要显示的指明!
publicstaticvoid swap(MyInteger i, MyInteger j)
{
    i.setValue(40);
    j.setValue(50);
}
swap((MyInteger)a.clone(),(MyInteger)b.clone());
 
 
3.5 思考下面的例子
 
 package hziee; 
 
publicclass StringTest
{
    staticvoid func(String s)
    {
        s += "tail";
    }
 
    staticvoid test()
    {
        String a = "abc";
        func(a);
        System.out.println(a);
    }
 
    publicstaticvoid main(String[] args)
    {
        test();
    }
}
 
看了上面的介绍内容应该明白是什么原因了吧?
原创粉丝点击