关于Java的值传递和引用传递

对于参数的传递有按值传递和按引用传递,

  • 我们首先来看个按值传递的例子
public class A {

    private static void change(int a) {
        a = -1;
    }

    public static void main(String[] args) {

        int num = 10;
        change(num);
        System.out.println(num); //num=10
    }
}

在上述代码中,add函数传递的参数是num的一份拷贝,这个过程发生在栈中,下面简单的画一下示意图。

这里写图片描述

首先要声明的是这个图是个简单的示意图,并不严谨,首先int类型在内存中需要4个字节的存储地址,而不是一个字节,引用也是一样。
不过我们通过这个图大致的说一下值传递的过程,在调用函数add的时候,参数通过栈进行传递,在栈中创建一个新的变量a并将num的值赋给它,当执行函数add的时候,a的值修改为-1,并不会使num产生任何变化。

  • 再看一个按引用传递的例子
public class A {

    private static void change(int[] a) {

        if(a==null || a.length==0)
            return;

        a[0] = -1;
    }

    public static void main(String[] args) {

        int[] num = {10};
        System.out.println(Arrays.toString(num));  //输出结果   [10]
        change(num);
        System.out.println(Arrays.toString(num));    //输出结果   [-1]
    }
}

可以看到在change函数中对参数a的修改,直接影响到了num的值,我们再简单的看一下内存示意图。

这里写图片描述

我们看到数组是在堆中分配的,在栈中num类型的变量指向堆中的地址,当调用change函数的时候,变量a也指向了0x100这个地址,也就是变量num和a指向的堆中的同一块地址,因此当a修改其本身指向数组值的时候,修改的是堆中的值,num也会受到影响。

  • 再看一个可能会混淆的例子
class User {
    int a;
}

public class D{

    void swap(User user1, User user2) {
        User temp;
        temp = user1;
        user1 = user2;
        user2 = temp;
    }

    public static void main(String[] args) {
        User u1 = new User();
        u1.a = 1;
        User u2 = new User();
        u2.a = 2;
        System.out.println(u1.hashCode()); // 输出 705927765
        System.out.println(u2.hashCode()); // 输出366712642
        System.out.println(u1.a); // 输出 1
        System.out.println(u2.a); // 输出2
        new D().swap(u1, u2);
        System.out.println(u1.hashCode()); // 输出 705927765
        System.out.println(u2.hashCode());// 输出366712642
        System.out.println(u1.a); // 输出 1
        System.out.println(u2.a); // 输出2
    }
}

在这里我们声明了两个对象u1和u2并分别对对象中a的值进行了初始化,我们在这里调用swap函数对两个对象进行了交换,但是发现u1和u2并没有交换,在交换后其内容依然相等,hash值也依然相等。我们看一下简单的内存示意图。

这里写图片描述

图可能略微有些抽象,捂脸。。。
我们看一下,当声明u1和u2的时候,内存示意图如黑线所指,u1指向了堆中的0x100地址,u2指向了内存中的0x103地址。
当调用swap函数的时候,两个参数user1指向了0x100的地址,user2指向了0x103的地址,如绿颜色线所示。
但是在swap函数中交换user1和user2的时候,其真实的结果是在栈中将两个变量的内容也就是其所指向的堆中的地址进行了交换,交换的结果是uaer2指向了0x100,user1指向了0x103,如红线所示,其交换的并不是堆中所指向对象的内容。因此,u1和u2并没有受到影响,也就是并没有产生交换。

  • 再最后看一个字符串的例子
public class A {

    private static void change(String string) {

        string = "11111";
    }

    public static void main(String[] args) {

        String str = "00000";
        change(str);
        System.out.println(str); 
    }
}

正确的输出结果为“00000”,我们再简单看下内存示意图。

这里写图片描述

因为在java语言中字符串的值是不可以变的,在对字符串修改的时候,而是直接产生一个新的字符串,因此修改变量string的结果是指向了一个新的地址0x105,str并没有受到影响。
关于字符串在内存中存储位置的探讨可以看另外一篇博客:http://blog.csdn.net/dingpiao190/article/details/72831125

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值