java的参数传递

来源:互联网 发布:视频提取软件 编辑:程序博客网 时间:2024/06/05 02:03

很早就知道java的数据类型分为基本数据类型(int,double,boolen等)和引用数据类型,所有的类对象其实都是一个引用数据类型。如果方法的参数是类对象,那么对其的操作是可以反映到对象本身的;但是如果参数是基础数据类型,在方法中对其的操作没法反映到原数据上。

举一个老掉牙的例子:

常见错误1

public class Main {    public static void main(String[] args) {        int a = 1;        int b = 2;        swap(a, b);        System.out.printf("a: %d, b: %d\n", a, b);    }    public static void swap(int num1, int num2) {        int tmp = num1;        num1 = num2;        num2 = tmp;    }}
a: 1, b: 2

由于是值传递,所以swap改变其实是a 和 b 克隆后的两个变量,而对这两个变量的操作不会对a 和 b产生任何影响。但是如果参数是一个类对象,我们对其的改变是可以反映到原对象实例的:

正确代码

public class Main {    public static void main(String[] args) {        AuxClass a = new AuxClass(1);        System.out.println("hashcode a: "+a.hashCode());        AuxClass b = new AuxClass(2);        System.out.println("hashcode b: "+b.hashCode());        swap(a, b);        System.out.println("hashcode a: "+a.hashCode());        System.out.println("hashcode b: "+b.hashCode());        System.out.printf("a: %d, b: %d\n", a.num, b.num);    }    public static void swap(AuxClass a, AuxClass b) {        int tmp = a.num;        a.num = b.num;        b.num = tmp;    }    static class AuxClass {        int num;        public AuxClass(int n) {            num = n;        }    }}
hashcode a: 589586037hashcode b: 682976601hashcode a: 589586037hashcode b: 682976601a: 2, b: 1

可以看到,a 和 b 对象的num的值改变了。上面是正确的写法,但是,很多人,包括我自己也犯过一个错误,那就是直接修改参数本身!怎么说呢,我们直接来看代码:

常见错误2

    public static void swap(AuxClass a, AuxClass b) {//      int tmp = a.num;//      a.num = b.num;//      b.num = tmp;        AuxClass tmp;        tmp = a;        a = b;        b = a;    }

输出则变为:

hashcode a: 589586037hashcode b: 682976601hashcode a: 589586037hashcode b: 682976601a: 1, b: 2

遇到这个错误的时候我才发现自己以前的一个理解错误:
java中不存在C中的“传引用”,只有值传递!!!!!


熟悉C的程序员都用过指针,对指针可谓爱之深恨之切。指针是指向一块内存地址的内存数据,也就是说指针本身是一个占用4字节内存的int(32 位系统内),而这个int值恰恰又是另一块内存的地址。比如”hello”这个字串,存放在@0x0000F000这个地址到@0x0000F005这段内存区域内(包括0x00的结束字节)。而在@0x0000FFF0到@0x0000FFF03这四个字节内存放着一个int,这个int的值是 @0x0000F000。这样就形成了一个指向”hello”字串的指针。

所以上面【常见错误2】中的swap方法,是将对象实例 a 和 b 的地址(指针)克隆过来,注意,这里我说的是“克隆”;我们姑且用aPointor 和 bPointer称呼它们,它们是新建的两个零时变量,在内存中是占用内存空间的。如果我们通过aPointor 和 bPointer去调用类的成员变量,是可以的,因为它们就是 a和b 实例的地址;但是,然后我们改变 aPointor 和 bPointer的值,那么也就仅仅是改变了两个零时变量,对于实例 a 和 b是没有任何影响的。这也是为什么我在【正确代码】和【常见错误2】中都输出了两个实例的hashCode,从它们的hashCode可以看出,它们的地址从未改变过。

所以,如果是从C/C++转到Java的程序员往往会不习惯这一点,因为在C中,可以传引用,而且【使用参数保存返回值】 或者 【一个方法返回多个值】 在C中是常用技巧,但是在Java中就没有那么方便,不过也并不困难,那就是用一个容器或者自己写一个新的类,把这些参数保证一下。就像前面分析的,通过引用变量操作其对应的实例的成员变量是可以的,但是直接操作引用变量本身是错误的。

0 0