理解Java传参是值传递

学习来源:
出自:@Ryan Miao
链接:https://www.cnblogs.com/woshimrf/p/5263018.html

先看一段代码:

/**
 * 调式运行,理解java的值传递
 */
public class ReferenceAndValue {
    public String change(String s2, int i2, StringBuffer sb2, Person p2){
        s2 = "123";
        i2 = 3;
        sb2.append("woshi");
        p2.setAge(100);
        sb2 = new StringBuffer("sbsb");
        p2 = new Person("bb",44);
        return  s2;
    }

    @Test
    public void testChange(){
        StringBuffer sb = new StringBuffer("buff");
        String s = "aaa";
        int i = 1;
        Person p = new Person("aa",12);
        i=2;
        change(s,i,sb,p);
        System.out.println(s);  //aaa
        System.out.println(i);  //2
        System.out.println(sb.toString());  //buffwoshi
        System.out.println(p);  //aa,100
    }
}

理解:

1、首先是String类型

抽取出String类型的主要代码
在这里插入图片描述

打断点,调式的过程如下

1.s指向aaa的后。
在这里插入图片描述

2、进入change方法后,赋值前。
在这里插入图片描述

可以看到进入change方法后,是形参s2来接收“aaa”的地址值,可以理解成把s的引用地址复制给s2。拓展理解:这算是由testChange“栈帧”来到了另一个change“栈帧”,关于栈帧介绍可以参考《深入理解Java虚拟机 》第3版。所以可以看到调式Variable中的变量都变成了s2,i2,sb2,p2。

3、在change方法中,完成s2的赋值后。
在这里插入图片描述

可以看到s2的引用地址值改变了,指向了“123”。由于String是不可变的,所以新生成了一个字符串常量,然后s2指向了它。注意,原本已有的“aaa”字符串还是存在字符串常量池中。

4、执行完change方法,回到testChange方法。
在这里插入图片描述
小结:

可以看到testChange方法中的变量s作为实参,传递给change方法的形参s2,传递的是s的引用地址。这可以看成是把s的值(引用地址)复制了一份给s2,此时s2也就指向了"aaa";这就很好地理解了Java传参是值传递。

注意区分s的引用s的值

反过来想下,如果是引用传递,那传参应该传递的是s的引用而不是s的值s的值是引用对象地址@867。


2、然后是基本数据类型

基本数据类型传参就是值传参,这个就容易理解了。这里就不多加解释了,传参就是简单的值传递,由于i=2;所以把i值2传递给形参i2,那此时i2=2;然后在change方法里面对i2的值进行修改,i2=3,这个修改对testChange中的i值是没有影响的,所以testChange中的i值还是2。


3、再来看看StringBuffer

1、初始化StringBuffer sb,sb指向了@852;
在这里插入图片描述
2、进入change方法,执行append方法前
在这里插入图片描述
由形参sb2接收sb的引用地址值,此时sb2指向“buff”,注意sb2指向某个引用地址值sb2本身的地址值是不一样的

3、sb2执行append方法后,sb2=new StringBuffer(“sbsb”)前;
在这里插入图片描述
可以看出,执行sb2.append(“woshi”),只是在sb2原来指向的引用地址值@852的字符串常量后添加"woshi"。

4、sb2=new StringBuffer(“sbsb”)后,返回testChange方法前。
在这里插入图片描述
注意,由于第三步执行了sb2.append(“woshi”);那之前的@852的值就变成了“buffwoshi”。然后,sb2指向了new StringBuffer(“sbsb”)生成的新地址@892。此时,testChange()方法中的sb依然指向@852,只不过@852的值变成了“buffwoshi”;见证在下一步,也就是返回testChange()方法后。

5、返回testChange方法后。
在这里插入图片描述
小结:
StringBuffer这小节的整个过程中,sb始终指向@852。然后在传参给sb2的时候,复制了一份引用对象的地址值@852给sb2,接着sb2对@852的值添加了“woshi”,再接着sb2指向了新的地址@892。最后返回testChange方法,sb的指向没有变。


4、Person引用对象

自定义类型在方法传参的过程也一样的道理。


大总结:

1、解答了String类型传参的时候,为什么在另一个方法里对String引用类型进行修改,然而在testChange方法中打印String变量还是原来的值,这是因为String类型是不可变的,它在change方法里赋新值,是另外创建了新的字符串常量,而不是对原来的字符串进行修改。

2、解答了为什么其他引用类型传参的时候,为什么它的值被改变了。这是因为传递的值就是Person引用对象的地址。然后在change方法中,对该引用对象地址的值进行了修改,所有在testChange方法中打印的值是改变的。

3、解答了为什么基本数据类型传参的时候,即使change方法在接收基本数据类型后,进行修改,而在testChange方法打印出来的值是没有变的。

注意:

  • 对象本身的地址和引用类型对象的地址两者的区别
  • String字符串常量是不可变的。如果对它进行赋值,则是改变了它的引用。

—end

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值