请考虑以下示例.

String str = new String();

str  = "Hello";
System.out.println(str);  //Prints Hello

str = "Help!";
System.out.println(str);  //Prints Help!

现在,在Java中,字符串对象是不可变的.那么,为什么对象str可以被赋予"帮助"的值呢.这不是与Java中字符串的不变性相矛盾吗?谁能给我解释一下不变性的确切概念吗?

编辑:

好啊我现在明白了,但只有一个后续问题.那么下面的代码呢:

String str = "Mississippi"; 
System.out.println(str); // prints Mississippi 

str = str.replace("i", "!"); 
System.out.println(str); // prints M!ss!ss!pp! 

这是否意味着会再次创建两个对象("密西西比"和"M!ss!ss!pp!")参考str指的是replace()法之后的另一个物体?

推荐答案

str不是一个对象,它是对一个对象的引用."Hello""Help!"是两个截然不同的String对象.因此,str points to是一根弦.你可以改变它points to的内容,但不能改变它points at的内容.

以下面的代码为例:

String s1 = "Hello";
String s2 = s1;
// s1 and s2 now point at the same string - "Hello"

现在,我们对s1所做的一切都不会影响s2的值.它们指的是同一个对象——字符串"Hello"——但该对象是不可变的,因此不能更改.

如果我们做这样的事:

s1 = "Help!";
System.out.println(s2); // still prints "Hello"

这里我们看到了改变对象和改变引用之间的区别.s2仍然指向我们最初设置的s1指向的同一个对象.将s1设置为"Help!"只会更改reference,而它最初引用的String对象保持不变.

如果字符串是可变的,我们可以这样做:

String s1 = "Hello";
String s2 = s1;
s1.setCharAt(1, 'a'); // Fictional method that sets character at a given pos in string
System.out.println(s2); // Prints "Hallo"

Edit to respond to OP's edit:

如果您查看source code for String.replace(char,char)(也可以在JDK安装目录中的src.zip中找到——一个专业提示是,每当您想知道某些东西是如何工作的时,都可以查看它),您可以看到它的功能如下:

  • 如果当前字符串中出现一个或多个oldChar,请复制当前字符串,其中所有出现的oldChar都替换为newChar.
  • 如果oldChar不在当前字符串中,请返回当前字符串.

是的,"Mississippi".replace('i', '!')创建了一个新的String对象.同样,以下观点成立:

String s1 = "Mississippi";
String s2 = s1;
s1 = s1.replace('i', '!');
System.out.println(s1); // Prints "M!ss!ss!pp!"
System.out.println(s2); // Prints "Mississippi"
System.out.println(s1 == s2); // Prints "false" as s1 and s2 are two different objects

你现在的作业(job)是看看如果你把s1 = s1.replace('i', '!');改成s1 = s1.replace('Q', '!');,上面的代码会做什么:)


1实际上,改变字符串(和其他不可变对象)是可能的.它需要反思,非常非常危险,除非你真的有兴趣销毁这个程序,否则永远不要使用它.

Java相关问答推荐

长音符

Collections.binarySearch()使用Collections.reverseOrder()作为比较器返回-1

如果给定层次 struct 级别,如何从其预序穿越构造n元树

Android视图覆盖不阻止点击它后面的控件

Javascript在边界中心调整ImageView大小

Java List with all combinations of 8 booleans

我需要生成一个文件来整合每个特性执行的所有JSON结果

为什么Java编译器不区分不同类型的方法?

与Spring Boot相关的实体未正确保存

如何解释Java中for-each循环中对Iterable的强制转换方法引用?

用OSQL创建索引

Android Studio模拟器没有互联网

如何在运行docker的应用程序中获取指定的配置文件

如何使用jooq更新记录?

协同 routine 似乎并不比JVM线程占用更少的资源

谷歌应用引擎本地服务器赢得';t在eclipse上运行

Java编译器是否进行了持续的折叠优化,以及如何进行判断?

如何用Micrometer&;斯普肯

SonarQube在合并升级到java17后对旧代码提出错误

java 11上出现DateTimeParseException,但java 8上没有