为什么下面的例子似乎反驳了 String 是 Java 中不可变对象的说法?
我在Ubuntu下使用OpenJDK Java编译器。我想将字符数组转换为字符串,当这似乎最终给出了不明确的结果时,我尝试编写自己的 toString
方法。在此过程中,我编写了一个测试程序,其中(出于乐趣)我尝试编译以下代码。
class toString{
public static void main(String[] args){
string = "abc";
string = string + "bcd";
System.out.println(string);
}
}
现在,我知道 Java 中的 String
对象是不可变的,代码实际上应该生成错误,但令我惊讶的是,它将 abcbcd
打印到控制台。这是否意味着 Java 中的 String
对象是可变的,或者在这种情况下 OpenJDK 编译器的实现存在问题?
I am using the OpenJDK Java compiler under Ubuntu. I wanted to convert a character array to a string and when that seemed to have ended up giving ambiguous results, I tried to write a toString
method of my own. In the process, I wrote a test program wherein (out of the fun of it) I tried to compile the following code.
class toString{
public static void main(String[] args){
string = "abc";
string = string + "bcd";
System.out.println(string);
}
}
Now, I know that String
objects in Java are immutable and the code should have in fact generated an error but to my surprise, it printed abcbcd
to the console. Does this mean that String
objects in Java are mutable or is there something wrong with the implementation of OpenJDK compiler in this case?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
您上面发布的代码实际上不会改变任何字符串,尽管看起来确实如此。原因是该行不会改变字符串:
相反,它的作用是:
string + "bcd"
的新字符串。string
引用的字符串以引用此新字符串。换句话说,实际的具体字符串对象本身并没有改变,但是对这些字符串的引用确实被修改了。 Java 中的不变性通常意味着不能修改对象,而不是对这些对象的引用。
令许多新 Java 程序员感到困惑的一个重要细节是,上面的行通常被写成
看起来更强烈的样子,就好像它将
bcd
连接到字符串的末尾,从而改变了它,尽管它与上面的代码等效,因此不会对实际的String
对象造成任何更改(同样,它的工作原理是创建一个新的String
对象并更改引用的对象指的是。)看到这里发生的事情是,您实际上正在更改引用而不是它引用的字符串,您可以尝试重写代码以生成
string
final
,这会阻止您更改引用的对象。如果这样做,您会发现代码不再编译。例如:最后一点 - 对于新 Java 程序员来说,使用
String
时另一个常见的原因是String
具有看似会改变字符串的方法,但实际上并没有。例如,此代码无法正常工作:此处,对
s.toLowerCase()
的调用实际上并未将字符串的字符转换为小写,而是生成具有字符集的新字符串为小写。如果您随后将代码重写为那么代码将正常运行。同样,这里的关键细节是对
s
的赋值不会更改任何具体的String
对象,而只是调整s
引用的对象。希望这有帮助!
The code that you've posted above does not actually mutate any strings, though it looks like it does. The reason is that this line doesn't mutate the string:
Instead, what this does is:
string + "bcd"
.string
to refer to this new string.In other words, the actual concrete string objects themselves weren't changed, but the references to those strings were indeed modified. Immutability in Java usually means that objects cannot be modified, not the references to those objects.
An important detail that confuses a lot of new Java programmers is that the above line is often written as
which looks even more strongly as though it's concatenating
bcd
onto the end of the string and thereby mutating it, even though it's equivalent to the above code and therefore doesn't cause any changes to the actualString
object (again, it works by creating a newString
object and changing what object the reference refers to.)To see that what's going on here is that you're actually changing the reference and not the string it refers to, you can try rewriting the code to make
string
final
, which prevents you from changing what object is referenced. If you do so, you'll find that the code no longer compiles. For example:One final note - another common cause of grief for new Java programmers when using
String
s is thatString
has methods that appear to mutate the string but in actuality do not. For example, this code does not work correctly:Here, the call to
s.toLowerCase()
does not actually convert the characters of the string to lower case, but instead produces a new string with the characters set to lower case. If you then rewrite the code asThen the code will behave properly. Again, the key detail here is that the assignment to
s
does not change any concreteString
object, but just adjusts what objects
refers to.Hope this helps!
不,没有错误 - 您没有更改任何字符串对象的内容。
您正在更改完全不同的字符串变量的值。将其视为两个操作:
string + "bcd"
的结果string
变量让我们分开明确地指出它们:
区分变量和对象非常重要。变量的值只是一个引用或原始类型值。更改变量的值不会更改它先前引用的对象的内容。
Nope, no error - you're not changing the contents of any string object.
You're changing the value of a string variable which is entirely different. Look at this as two operations:
string + "bcd"
string
variableLet's separate them out explicitly:
It's very important to distinguish between variables and objects. The value of a variable is only ever a reference or a primitive type value. Changing the value of a variable does not change the contents of the object to which it previously referred.
区别在于对象的引用和对象本身。
方法:
创建一个新变量并将引用分配给包含文字字符串“xxx”的对象 String 的实例。
含义:
获取对名为 XXX 的变量中的对象的引用。
创建一个 String 类型的新对象,其中包含字符串文字“yyy”。
执行字符串 + 运算符将它们添加在一起。
此操作将创建一个新的 String 对象,其中包含文字字符串“xxxyyy”。
完成这一切之后,我们再次将对新对象的引用放入变量 XXX 中。
包含“xxx”的旧引用对象不再使用,但其内容从未被修改。
作为反证,有一个例子:
对象实例是存在于程序内存的一部分中的“抽象”东西。引用变量是对该内存部分的引用。
您只能通过变量(或返回值)访问对象。
一个对象可以有多个指向它的变量。
String 是不可变的意味着您无法修改 String 对象使用的内存区域的内容,但是当然,您可以根据需要自由更改和交换对其的引用。
The difference is between References to an object and the object itself.
Means:
Make a new variable and assign the reference to an instance of object String that contains the literal string "xxx".
Means:
Get the reference to the object we have in variable named XXX.
Make a new object of type String that contains the string literal "yyy".
Add them together executing the string + operator.
This operation will create a new String object that contains the literal string "xxxyyy".
After all this, we put the reference to the new object again in the variable XXX.
The old referenced object containing "xxx" is not used anymore but the content of it was never modified.
As a counter proof, there is an example:
Object instance are something "abstract" that live in a portion of memory of your program. A reference variable is a reference to that portion of memory.
You can access objects only through variables (or return values).
A single object can have more than one variable pointing at it.
String is immutable means that you cannot modify the content of that area of memory used by the String object, but of course, you are free to change and exchange references to it as you prefer.
它并不反驳它。它实际上不会编译,因为 string 没有声明为 String 对象。但是,假设您的意思是:
请参阅 + 运算符创建一个新字符串,并保持“abc”不变。原来的“abc”仍然存在,但您实际上所做的只是创建一个新字符串“abcbcd”,并在执行以下操作时覆盖对“abc”的原始引用:string = string +“bcd”。如果您将该代码更改为这样,您就会明白我的意思:
It doesn't refute it. It actually won't compile since string isn't declared as a String object. But, let's say you meant:
See the + operator creates a new String leaving "abc" in tact. The original "abc" still exists, but all you've actually done is create a new string "abcbcd" and overwrite the original reference to "abc" when doing: string = string + "bcd". If you changed that code to this you'll see what I mean:
String
对象是不可变的,您只需将string
的值重新分配给string + "bcd"
你的代码示例。您不是修改现有的String
对象,而是创建一个新对象并将其分配给旧名称。String
objects are immutable, you are simply re-assigning the value ofstring
tostring + "bcd"
in your code example. You are not modifying the existingString
object, you are creating a new one and assigning it to the old name.string = string + "bcd"
将String
的新实例设置为变量string
,而不是修改该对象string = string + "bcd"
sets a new instance ofString
to the variablestring
, rather than modify that object它所做的就是创建一个新对象并替换旧对象。
如果您想要可变字符串,请查看字符串生成器。
what this will do is that it will make a new object, and replace the old one.
if you want mutable string look at string builder.
String
变量string
本身是可变的。String
对象"abc"
是不可变的,字符串对象"bcd"
也是如此,并且结果连接,“abbcbcd”
。最后的结果被分配给变量。在执行该代码片段时,没有字符串发生变化。
The
String
variablestring
itself is mutable.The
String
object"abc"
is immutable, as is the String object"bcd"
, and the result of the concatenation,"abcbcd"
. That last result is assigned to the variable.No String was mutated in the execution of that code snipped.
该字符串是不可变的...您的示例所做的只是表明您可以将新的字符串引用分配给变量。
如果我们编译代码,并稍微更改它:
您将看到“abc”,然后是“abcbcd”,这可能会让您认为字符串已更改,但实际上没有更改。
当您执行 string = /* 不管 */ 时,您将用新值覆盖 string 变量中原来的内容。
如果 String 有一个方法,例如 setCharAt(int index, char value) 那么它就是可变的。
The string is immutable... all your example does is show that you can assign a new string reference to a variable.
If we make the code compile, and change it slightly:
You will see "abc" and then "abcbcd" which, could lead you to think that the string has changed, but it has not.
When you do the string = /* whatever */ you are overwriting what used to be in the variable called string with a new value.
If String had a method, such as setCharAt(int index, char value) then it would be mutable.