java字符串是引用吗_Java-Basics-Strings-字符串在Java中是通过“引用”传递的吗?...

这在Java中也算是一个经典的问题了

1有趣的代码

首先我们来看一段简单的Java代码,并猜一猜这段代码会输出什么?

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";

}

然后来看看C++的代码,同样看看会输出什么结果

void change(string &x) {

x = "cd";

}

int main(){

string x = "ab";

change(x);

cout << x << endl;

}

很简单,第一段的Java代码输出结果是ab,而第二段的C++代码输出的是cd,你答对了吗?

2令人困惑的问题

那么为什么会是这样呢?

要清楚的是x实际存储的是指向堆heap中“ab”字符串的引用(reference),所以当x作为一个参数传递到方法change()时,它仍旧指向堆中的字符串”ab“,如下图所示:

0818b9ca8b590ca3270a3433284dd417.png

因为Java是值传递(pass-by-value)的,所以x的值就是指向字符串"ab"的引用,当方法change()被触发之后,会生成一个新的对象"cd",那么这时候x就指向了这个新对象,如下图所示:

0818b9ca8b590ca3270a3433284dd417.png

这看上去似乎是一个非常合理的解释,许多人也非常清楚Java是值传递的,那么这个解释到底哪里有问题呢?

3代码实际上做了什么呢

上面的解释确实是有些问题的,为了搞清楚这些问题,我们就把这个过程好好地走一遍

当创建字符串“ab”的时候,Java会分配相应的内存来存储该对象;然后,该对象被赋给了变量x,这时候变量x就被赋予了引用从而指向了对象——字符串“ab”,该引用也就是创建字符串"ab"时分配的内存地址

变量x包含了指向字符串对象的引用,但是变量x自身却并不是一个引用!它是存储了一个引用(内存地址)的变量。

Java是仅有值传递(pass-by-value ONLY),也就是说当你把变量x作为参数传递给方法change()时,实际传递的是变量x的值(引用)的一份拷贝。方法change()生成了一个新的对象"cd",也就是有了一个完全不同的引用,所以实际上就是变量x改变了指向"cd"的引用,而不是引用本身。请看下图所示

0818b9ca8b590ca3270a3433284dd417.png

4错误的解释

第一段代码引起的这个问题和Java字符串的不变性没有关系,如果把String换成StringBuilder结果也是一样的。关键的一点就是变量存储的是引用而不是引用本身。

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");

}          简单总结以下:值传递,和地址传递比较起来是完全不同的,像上面的C++代码的地址传递比较好理解,因为传递的就是这个变量本身,所以变量所指的值确实是改变了;而值传递则相当于原变量的一个复制品,所以对复制品的操作不会对原来的变量产生任何影响。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值