简体   繁体   English

Java不可变字符串混乱

[英]Java immutable strings confusion

If String s are immutable in Java, then how can we write as: 如果String在Java中是不可变的,那么我们如何写为:

String s = new String();
s = s + "abc";

Strings are immutable. 字符串不可变的。
That means that an instance of String cannot change. 这意味着String实例无法更改。

You're changing the s variable to refer to a different (but still immutable) String instance. 您正在更改s 变量以引用另一个(但仍然是不可变的) String实例。

Your string variable is NOT the string. 您的字符串变量不是字符串。 It's a REFERENCE to an instance of String. 它是String实例的参考。

See for yourself: 你自己看:

String str = "Test String";
System.out.println( System.identityHashCode(str) ); // INSTANCE ID of the string

str = str + "Another value";
System.out.println( System.identityHashCode(str) ); // Whoa, it's a different string!

The instances the str variable points to are individually immutable, BUT the variable can be pointed to any instance of String you want. str变量指向的实例是单独不可变的,但该变量可以指向您想要的任何String实例。

If you don't want it to be possible to reassign str to point to a different string instance, declare it final: 如果您不希望将str重新分配给不同的字符串实例,请将其声明为final:

final String str = "Test String";
System.out.println( System.identityHashCode(str) ); // INSTANCE ID of the string

str = str + "Another value"; // BREAKS HORRIBLY

The first answer is absolutely correct. 第一个答案是绝对正确的。 You should mark it as answered. 你应该将其标记为已回答。

s = s+"abc" does not append to the s object. s = s+"abc"不会附加到s对象。 it creates a new string that contains the characters from the s object (of which there are none) and "abc". 它创建一个新的字符串,其中包含s对象(其中没有)和“abc”中的字符。

if string were mutable. 如果字符串是可变的。 it would have methods like append() and other such mutating methods that are on StringBuilder and StringBuffer. 它会有像append()这样的方法以及StringBuilder和StringBuffer上的其他类似的变异方法。

Effective Java by Josh Bloch has excellent discussion on immutable objects and their value. Josh Bloch的有效Java对不可变对象及其价值进行了很好的讨论。

Immutable Classes are those whose methods can change their fields, for example: 不可变类是那些方法可以改变其字段的类,例如:

Foo f = new Foo("a");
f.setField("b"); // Now, you are changing the field of class Foo

but in immutable classes, eg String, you cannot change the object once you create it, but of course , you can reassign the reference to another object. 但是在不可变类中,例如String,一旦创建它就无法更改对象,但当然 ,您可以将引用重新分配给另一个对象。 For example: 例如:

String s = "Hello";
s.substring(0,1); // s is still "Hello"
s = s.substring(0,1); // s is now referring to another object whose value is "H"
   String s = new String();  

Creates a new, immutable, empty string, variable "s" references it. 创建一个新的,不可变的空字符串,变量“s”引用它。

   s = s+"abc";              

Creates a new, immutable, string; 创建一个新的,不可变的字符串; the concatenation of the empty string and "abc", variable "s" now references this new object. 空字符串和“abc”的串联,变量“s”现在引用这个新对象。

Just to clarify, when you say s = s+"abc"; 只是为了澄清,当你说s = s +“abc”时; That means, create a new String instance (which is composed of s and "abc") then assign that new String instance to s. 这意味着,创建一个新的String实例(由s和“abc”组成),然后将新的String实例分配给s。 So the new reference in s is different from the old. 所以s中的新引用与旧引用不同。

Remember, a variable is effectively a reference to an object at some specific memory location. 请记住,变量实际上是对某个特定内存位置的对象的引用。 The object at that location stays at that location, even if you change the variable to refer to a new object at a different location. 即使您更改变量以引用其他位置的新对象,该位置的对象也会保留在该位置。

String s = new String();

An empty String object ( "" ) is created. 创建一个空String对象( "" )。 And the variable s refers to that object. 变量s指的是那个对象。

s = s + "abc";

"abc" is a string literal (which is nothing but a String object, which is implicitly created and kept in a pool of strings) so that it can be reused (since strings are immutable and thus are constant). "abc"是一个字符串文字(它只是一个String对象,它是隐式创建并保存在字符串池中),因此可以重用它(因为字符串是不可变的,因此是常量)。 But when you do new String() is totally different because you are explicitly creating the object so does not end up in the pool. 但是当你做new String()完全不同,因为你明确地创建了对象,所以不会在池中结束。 You can throw is in the pool by something called interning. 你可以通过一个叫做实习的东西扔进游泳池。

So, s + "abc" since at this point concatenation of and empty string ( "" ) and "abc" does not really create a new String object because the end result is "abc" which is already in the pool. 所以, s + "abc"因为此时和空字符串( "" )和"abc"并没有真正创建一个新的String对象,因为最终结果是已经在池中的"abc" So, finally the variable s will refer to the literal "abc" in the pool. 所以,最后变量s将引用池中的文字"abc"

I believe you are all making this much more complicated than it needs to be, and that simply confuses people who are trying to learn! 我相信你们所做的一切都比它需要的复杂得多,而这简直困扰了那些想要学习的人!

The primary benefit of making an object immutable in Java is that it can be passed by reference (eg to another method or assigned using the assignment operator) without having to worry about downstream changes to the object causing issues in the current method or context. 使对象在Java中不可变的主要好处是它可以通过引用传递(例如,传递给另一个方法或使用赋值运算符分配),而不必担心对象的下游更改导致当前方法或上下文中的问题。 (This is very different than any conversation about the thread safety of an object.) (这与关于对象的线程安全性的任何对话非常不同。)

To illustrate, create an application that passes a String as a parameter to a separate method, and modify the String in that method. 为了说明,创建一个将String作为参数传递给单独方法的应用程序,并修改该方法中的String。 Print the String at the end of the called method and then after control returns to the calling method. 在被调用方法的末尾打印String,然后在控制返回到调用方法之后。 The Strings will have different values, and that's because they point to different memory locations, a direct result of "changing" the immutable String (creating a new pointer and pointing it to a new value behind the scenes). 字符串将具有不同的值,这是因为它们指向不同的内存位置,这是“更改”不可变字符串的直接结果(创建新指针并将其指向幕后的新值)。 Then create an application that does the same things except with StringBuffer, which is not immutable. 然后创建一个执行相同操作的应用程序,除了StringBuffer,它不是不可变的。 (For example, you can append to the StringBuffer to modify it.) The printed StringBuffers will have the same values, and that is because it is (a) being passed by reference, as Java does with all objects passed to methods as parameters and (b) mutable. (例如,您可以附加到StringBuffer来修改它。)打印的StringBuffers将具有相同的值,这是因为它是(a)通过引用传递,因为Java将所有对象作为参数传递给方法, (b)可变的。

I hope this helps folks who are reading this thread and trying to learn! 我希望这能帮助正在阅读这个主题并试图学习的人们!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM