为什么修改字符串数组元素后字符串不会改变

3
我不明白为什么字符串不能像对象一样工作,即当你改变它时,它所分配的变量也会随之改变。
我曾尝试过创建一个字符串数组,然后将其中一个元素的引用分配给一个变量(我说引用是因为据我所知Java是按值传递,而一个内存引用就是那个“值”)。但是当我改变了字符串元素时,变量并没有反映出这种变化。
String[] arr={"abc","def"};

String s=arr[1];

arr[1]+="123r";

for (String i:arr) {System.out.print(i);}

System.out.println(); // prints "abcdef123r"

System.out.println(s); //prints "def"

也许根据我所读到的,赋值操作符对于字符串并不像这样起作用。

2
字符串不像对象一样工作,当你改变它时,分配给它的变量也会改变。字符串是对象,并且与任何其他对象完全相同。arr[1] +="123r"并不会“更改对象”。它等同于arr[1] = arr[1] + "123r",即创建一个新的字符串对象,并将该新的字符串对象存储在数组中,索引为1。 - JB Nizet
哦,所以赋值运算符确实没有按预期工作。 - user134505
3个回答

6

字符串是不可变的。这意味着它们的值永远不会改变。它们的引用可以被重新分配,这就是这里发生的事情。

在评论中有一个时间线:

// Create two Strings. [string1]="abc", [string2]="def"
// Assign [string1] to arr[0]. 
// Assign [string2] to arr[1].
String[] arr={"abc","def"};

// Get value from arr[1] = [string2]
// Assign [string2] to s
String s=arr[1];

// Get value from arr[1] = [string2]
// create [string3] = "123r"
// create [string4] = [string2] + [string3]
// assign [string4] to arr[1]
arr[1]+="123r";

// get value from arr[0] = [string1]
// print [string1] = "abc"
// get value from arr[1] = [string4]
// print [string4] = "def123r"

for (String i:arr) {System.out.print(i);}

System.out.println(); // prints "abcdef123r"

// get value from s = [string2]
// print value "def"
System.out.println(s); //prints "def"

我说“引用(reference)”,因为据我所了解,Java是按值传递(pass by value),而内存引用就是那个“值”。 几乎正确。
引用(reference)是一个地址。可以在该地址的内存中找到相应的值。
所以你所拥有的是:
变量 = 人类可读。苹果(apple)。
引用(reference) = 计算机可读的内存地址。
值(value) = 存储在给定地址的一些字节(byte)。
所以当你进行以下操作时:
 String s = arr[1];

您正在将链接到变量 arr [1] 的内存地址分配给变量 s 。 RAM中的值保持不变,不会发生更改。

当您执行

 arr[1] += "123r";

你正在创建一个全新的字符串。
具体步骤如下。
arr[1] += "123r";
arr[1] = arr[1] + "123r"; 
arr[1] = "def" + "123r";
arr[1] = "def123r";

因此,arr[1]被分配了操作结果的内存地址/引用。
然而,这个操作与变量s没有任何关系,因为这个变量保存着原始字符串的地址,而且没有代码来更新那个引用/内存地址。


1
哦!我明白了,不可变性的那一部分非常有启发性。 感谢您详细而有帮助的评论。 - user134505

2

简而言之,您遇到的行为是符合预期的。在Java中,字符串被设计为不可变的,也就是说它们的值无法改变。

字符串不可变性意味着什么?

研究下面的代码片段,并尝试在不运行代码的情况下预测输出结果。

最初的回答:

简而言之,您遇到的行为是符合预期的。在Java中,字符串被设计为不可变的,也就是说它们的值无法改变。

什么叫做字符串不可变性?

请观察以下代码片段并尝试预测输出结果,不必实际运行代码。

 String s = "Stack";  
 s.concat(" overflow"); 
 System.out.println(s);

你期望输出的结果是什么?“堆栈溢出”对吧?但不,实际输出结果是“Stack”。你可以自行测试验证。这正是字符串的行为方式。
当然,我们可以通过以下更改来让代码按照我们想要的方式运行:
 String s = "Stack";  
 s = s.concat(" overflow"); 
 System.out.println(s);

这样做会创建一个新对象,输出结果为堆栈溢出

希望这能帮到你。愉快的编程! 编辑过的


1

我们知道,在Java中,字符串是一个常量变量。

  1. String[] arr={"abc","def"}

    常量字符串池: "abc", "def"

    arr[0] -> "abc"

    arr[1] -> "def"

  2. String s=arr[1]

    常量字符串池: "abc", "def"

    arr[0] -> "abc"

    arr[1] -> "def"

    s -> "def"

  3. arr[1]+="123r"

    常量字符串池: "abc", "def", "def123r", "123r"

    arr[0] -> "abc"

    arr[1] -> "def123r"

    s -> "def"


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接