String作为参数传递到底是值传递还是引用传递?

我们首先看一下下面这样一段代码,它的输出结果是什么? 

public static void main(String[] args) {
        String s1=new String("张三");
        change(s1);
        System.out.println(s1);
    }
public static void change(String s2){
        s2="李四";
    }

我一开始一看,String是引用类型,引用类型是引用传递。那么结果应该是“李四”,但是实际运行结果是“张三”,这个结果让我很蒙。引用类型难道不是引用传递吗?随后我又自定义了一个类Person来测试

public class Person {
    String name;
    public Person(String name){
        this.name=name;
    }
}

public static void main(String[] args) {
        Person p1 = new Person("张三");
        change(p1);
        System.out.println(p1.name);
}
public static void change(Person p2){
        p2.name="李四";
}

这次运行的结果是“李四”。这时为什么值又改变了呢?Person是引用类型,是引用传递。难道String不是引用类型,又或者它是值传递?为了弄清楚这个问题,我也在网上看了许多文章 ,把我头都搞晕了。后来结合我所看到的文章,慢慢的理清了头绪。接下来我就讲一下我的看法,有讲的不对之处还烦请指正。

 首先我们不要纠结于它到底是值传递,还是引用传递。java在方法传递参数时,是将变量复制一份,然后传入方法体执行。这句话到底什么意思呢?对于基本数据类型传值,相信大家很容易理解,它是传递的一个具体值。但是对于引用类型,是将对象在堆中的地址进行复制一份进行传递,所以这样从某种程度看来它本质上还是值传递。明白了这一点,接下来我们回到上面的第一个问题(String类型作为参数传递)。

1.第一个问题在jvm中的存储如下(还未调用change(s1)时)

  • 首先 String s=new String("张三"),在堆中开辟内存放对象,变量s1在栈中,存放的是堆的地址
  • 将地址0x11复制一份给s2,此时s2放的是地址0x11
  • 接下来再看s2="李四";要知道通过=赋值是直接先去常量池寻找是否存在与“李四”相同的值,有的话直接将其地址返回。否则创建一个值,再返回其地址。

那么调用change(s1)后,再看它在jvm中存储变化

 这么来看就十分清晰了,s1和s2最终存储的地址不同。

我们再来看第二个问题(自定义对象Person传参为何最后值发生了改变)

  • 首先 Person s=new Person("张三"),在堆中开辟内存放对象,变量p1在栈中,存放的是堆的地址
  • 将地址0x11复制一份给s2,此时s2放的是地址0x11
  • 接下来再看p2.name="李四";要知道通过=赋值是直接先去常量池寻找是否存在与“李四”相同的值,有的话直接将其地址返回。否则创建一个值,再返回其地址。与上一问题不同的是,这里我们改变的是name,而name在堆中,所以常量池中地址是复制给了name

 所以最后改变后的结果如下图所示

 

  • 17
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IABQL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值