通过引用传递字符串

这是一个经典问题。有很多类似的问题在stackoverflow上被提问且存在很多错误的、不完整的答案。如果您不去深究这个问题很简答。但是如果你深入去探究,又会令你很困惑。

1.一段有趣又令人困惑的代码片段

public static void main(String[] args) {
	String x = new String("ab");
	change(x);
	System.out.println(x);
}
 
public static void change(String x) {
	x = "cd";
}

上面代码会输出ab。

在C++中:

void change(string &x) {
    x = "cd";
}
 
int main(){
    string x = "ab";
    change(x);
    cout << x << endl;
}


输出:cd

2.常常令人困惑的问题

x存储着指向堆中字符串对象”ab“的引用。所以当x作为参数传递给change()方法,它仍然指向在堆中的”ab“,像下图这样:

因为Java是值传递的,所以x的值是指向”ab“的引用。当方法change()被调用时,它会创建一个新的对象”cd“。现在x指向”cd“,像下图这样:

似乎是一个令人信服的解释。这完全符合Java总是通过值传递的结论。但是哪里出错了呢?

3.这段代码到底如何工作的


上面的解释有几处错误。为了更好的理解,我们简单介绍一下整个过程。
当字符串”ab“被创建的时候,Java分配了可以存储这个字符串大小的内存,这个字符串对象赋值给变量x,变量x实际上获得了指向这个对象的引用。这个引用是字符串对象存储在内存中的地址。
变量x包含指向这个字符串对象的引用。x本身并不是一个引用。它是存储一个引用的变量。
Java仅存在值传递。当x被传递给方法change()时,传递给这个方法的是x的一份拷贝。change()方法创建了另外一个对象cd,有一个不同引用指向它。变量x改变了指向字符串对象”cd“的引用,而不是引用本身。
下图向我们展示了事情的真相。

4.错误的解释


上面的代码片段引出的问题与字符串的不可变性没有关系。即使用StringBuilder代替String,结果也是相同的。问题的关键是那个变量存储了引用,但它不是引用本身。

5.如何避免上面的问题


如果我们确实需要改变对象的值。首先,这个对象可以被改变,比如StringBuilder。第二,我们需要确保不会有新的对象被创建,然后赋给参数变量。因为Java是值传递的。
public static void main(String[] args) {
	StringBuilder x = new StringBuilder("ab");
	change(x);
	System.out.println(x);
}
 
public static void change(StringBuilder x) {
	x.delete(0, 2).append("cd");
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值