对于Java中只有值传递的理解

什么是值传递

值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

什么是引用传递

引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

注意: 值传递是把实际参数复制了一份传给形参,而引用传递是直接把实参的地址传了过去,并没有复制实参;

好了,当我们搞清楚 值传递和引用传递的概念之后,我们就可以用例子来证明Java里面到底有没有引用传递了。

public class TestValuePropagation {
    public static void main(String[] args){
        int m = 10;
        int n = 20;
        swap1(m,n);
        System.out.println("main:"+m+" "+n);
    }
    public static void swap1(int m, int n){
        int tmp = 0;
        tmp = m;
        m = n;
        n = tmp;
        System.out.println("swap1:"+m+" "+n);
    }
}//运行结果:
//swap1:20 10
//main:10 20

从输出结果可以看出来基本数据类型是采用的值传递,因为在swap1函数中并没有实现交换main()函数中变量m和n的值。
那我们接下来测试一下引用类型

 class TestValuePropagation2 {
    public static void main(String[] args) {
        B b1 = new B();
        testQuote(b1);
        System.out.println("a:" + b1.a);
    }

    public static void testQuote(B b) {
        b.a = 200;
    }

}
class B {
    int a = 100;
}//运行结果
//a:200

我们就单单从结果来看,类B里面的a的值被修改成200了,实参值被修改了,难道对于引用类型Java采用的是引用传递?其实不然,它之所以能够修改a的值是因为传过去的是一个对象句柄,也就是变相的传过去了a的地址。通过a的地址改变了a的值。我们接下来再通过一个例子验证一下到底是不是值传递

class TestValuePropagation3 {
    public static void main(String[] args) {
        B b2 = new B();
        testQuote(b2);
        System.out.println("a:" + b2.a);
    }

    public static void testQuote(B b) {
        b = new B();
        b.a = 200;
    }
    //运行结果
    //a:100
}

在这个程序里面a的值100并没有被修改,那为什么这个程序里面没有被修改呢?我们先看一下这两个程序的不同之处,第二个例子里面多了一句 b = new B(); 这条语句是实例化了一个对象,并且这个对象的句柄是b,本来b和b2是相等的,指向的同一块内存,现在通过赋值又把b变成新的对象句柄,b和b2就是两个不同的对象,所以下边修改a的值修改的就是新对象里面的a的值,而不是b2对象里面a的值。如果这里采用的是引用传递的话,那main函数里面的b2也应该被修改成为新对象的句柄,显然b2这里并没有被修改,由此可见函数形参即使是引用类型,java中也依然采取的是值传递。把实参b2复制了一份传给了b,当把b的指向内容修改之后,b和b2就不再是同一个对象。
下面我们从内存的角度分析一下更好理解
在这里插入图片描述

我们看上图,当我们调用那个函数的时候jvm会把b2里面的地址当成值复制一份传给b,所以第二个例子里面可以通过b里面存放的地址来修改a的值。然而当第三个例子里面执行完new B();这句话之后b里面存放的就不再是0x001这个地址了,存放的是另一个新对象的地址0x002,这个时候再去修改a,修改也不再是b2里面的a了。

这里有一个特殊的例子,我们来看一下

class TestValuePropagation4 {
    public static void main(String[] args) {
        String str = "hahaha";
        testQuote(str);
        System.out.println("main()str:" + str);
    }

    public static void testQuote(String str) {
        str = "hehehe";
        System.out.println("testQuote()str:" + str);
    }
}
//运行结果
//testQuote()str:hehehe
//main()str:hahaha

String也是一个类,在传参的时候传的也是拷贝后的地址,为什么修改不了str的值呢?难道传过去的是一个拷贝后的字符串?其实并不是这样的,引用类型传递的依然是拷贝后的地址,str之所以改不了和String这个类本身有关。我们接下来看一下他的源码就明白了

在这里插入图片描述
String 里面的值都是被final修饰过的,不可以修改的值,当你试图修改str的值的时候,jvm就会在String pool里面新建一个String对象来保存新的str的值,所以main()函数里面的str并不会被修改。
对于引用类型的传递,通俗一点讲就是我有一把我房间的钥匙,我的朋友也想来我家玩,但是他没有我家的钥匙,就没法进我家,只能我把我的钥匙借给他,让他进去。这就是相当于引用传递,他有了我家钥匙就可以随便来我家玩。而值传递就是我把我的钥匙复制了一个一模一样的给他,这样它也可以随便来我家玩 。

由此可见在 Java里面不管是数值类型,引用类型采用的都是值传递。(这里的值也可指地址)不能简单的认为传过去的是个数值就认为是值传递,传过去的是引用类型就是引用传递

本人新手一枚,经过这两天看资料和各位大佬的博客终于有点理解了Java中的传递,写篇博客希望和大家探讨一下。如果文中有错误的地方,欢迎大家指正。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值