理解Java中的字符串不变性

Jav*_*ast 0 java

在尝试理解为什么字符串是不可变的原因时,我写了一个简单的程序如下:

/* Program to test string immutability */

public class StringImmutability
{
    public static void main(String args[])
    {
        String s = "hello";
        s.concat(" world"); // returns a new string object. So, the reference must point to this object for further processing like this: s = s.concat(" world");
        System.out.println(s);
        s = s.concat(" world");
        System.out.println(s);
        String s1 = s, s2 = s, s3 = s;
        System.out.println(s1+" "+s2+" "+s3);
        s = s.concat(" test");
        //The references are modified
        System.out.println(s1+" "+s2+" "+s3); 
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然输出不符合预期:

hello
hello world
hello world hello world hello world
hello world hello world hello world
Run Code Online (Sandbox Code Playgroud)

修改引用后,输出必须hello world test重复三次,但输出没有任何变化.

Viv*_*ath 15

它完全按预期工作.让我们一步一步地看一下:

String s = "hello";
s.concat(" world");
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

这实际上是一个NOP,因为你没有将结果分配concat给任何东西.String由于没有任何内容涉及它,因此收集的以太和垃圾丢失了新实例.因此,你的s遗体不变.

s = s.concat(" world");
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

这里s.concat(" world")返回一个新String实例,并重新分配s给它.所以s现在指向这个字符串,你已经失去了对旧字符串的引用(刚才有一个字符串hello).

String s1 = s, s2 = s, s3 = s;
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

在这里,您创建了三个变量,这些变量都指向指向的同一个字符串实例s.

s = s.concat(" test");
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

这是您之前所做的重复.concat创建一个新的字符串实例,然后重新分配s给它.但是,请记住,s1,s2,和s3仍然指向什么s 用来指向,所以他们将不会反映更改.

你只是停止s指向旧字符串并使其指向新字符串.但是你的其他变量仍然指向那个旧字符串.


Hov*_*els 7

您的代码证明了字符串不变性.您可以更改变量引用的String,但是您无法更改String对象本身(除了通过我不会在这里讨论的狡猾的反射技巧).上面的错误在您的预期输出中,没有别的.例如,

s = s.concat(" test"); 
Run Code Online (Sandbox Code Playgroud)

创建一个新的 String对象并将其分配给s变量.它不会也不能改变所s引用的原始对象.


Sot*_*lis 6

s被重新分配给一个新的字符串,该字符串" test" String附加到目标值的末尾String(s预分配).

s = s.concat(" test");
Run Code Online (Sandbox Code Playgroud)

这不会影响该String值存储在s1,s2或者s3,因为concat返回一个新的String对象.