Java中字符串的不变性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1552301/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 14:02:11  来源:igfitidea点击:

Immutability of Strings in Java

javastringimmutability

提问by Light_handle

Consider the following example.

考虑以下示例。

String str = new String();

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

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

Now, in Java, String objects are immutable. Then how come the object strcan be assigned value "Help!". Isn't this contradicting the immutability of strings in Java? Can anybody please explain me the exact concept of immutability?

现在,在 Java 中,String 对象是不可变的。那么为什么对象str可以被赋值为“Help!”。这不是与 Java 中字符串的不变性相矛盾吗?任何人都可以向我解释不变性的确切概念吗?

Edit:

编辑:

Ok. I am now getting it, but just one follow-up question. What about the following code:

好的。我现在明白了,但只是一个后续问题。下面的代码怎么样:

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

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

Does this mean that two objects are created again ("Mississippi" and "M!ss!ss!pp!") and the reference strpoints to a different object after replace()method?

这是否意味着再次创建了两个对象(“Mississippi”和“M!ss!ss!pp!”)并且strreplace()方法之后引用指向不同的对象?

采纳答案by gustafc

stris not an object, it's a reference to an object. "Hello"and "Help!"are two distinct Stringobjects. Thus, strpoints toa string. You can change what it points to, but not that which it points at.

str不是一个对象,它是一个对象的引用。"Hello"并且"Help!"是两个不同的String对象。因此,str指向一个字符串。您可以更改它指向的内容,但不能更改它指向的内容

Take this code, for example:

以这段代码为例:

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

Now, there is nothing1we could do to s1that would affect the value of s2. They refer to the same object - the string "Hello"- but that object is immutable and thus cannot be altered.

现在,没有什么1,我们可以做些什么来s1会影响价值s2。它们引用同一个对象——字符串"Hello"——但该对象是不可变的,因此不能改变。

If we do something like this:

如果我们做这样的事情:

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

Here we see the difference between mutating an object, and changing a reference. s2still points to the same object as we initially set s1to point to. Setting s1to "Help!"only changes the reference, while the Stringobject it originally referred to remains unchanged.

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

If strings weremutable, we could do something like this:

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

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:

编辑以响应 OP 的编辑:

If you look at the source code for String.replace(char,char)(also available in src.zip in your JDK installation directory -- a pro tip is to look there whenever you wonder how something really works) you can see that what it does is the following:

如果您查看String.replace(char,char)源代码(也可以在您的 JDK 安装目录中的 src.zip 中找到——专业提示是每当您想知道某些东西是如何真正工作时就查看那里),您可以看到它的作用如下:

  • If there is one or more occurrences of oldCharin the current string, make a copy of the current string where all occurrences of oldCharare replaced with newChar.
  • If the oldCharis not present in the current string, return the current string.
  • 如果oldChar当前字符串中出现一个或多个,则复制当前字符串,其中所有出现的oldChar都被替换为newChar
  • 如果oldChar当前字符串中不存在 ,则返回当前字符串。

So yes, "Mississippi".replace('i', '!')creates a new Stringobject. Again, the following holds:

所以是的,"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

Your homework for now is to see what the above code does if you change s1 = s1.replace('i', '!');to s1 = s1.replace('Q', '!');:)

你现在做的功课,看看上面的代码确实如果你改变s1 = s1.replace('i', '!');s1 = s1.replace('Q', '!');:)



1Actually, it ispossible to mutate strings (and other immutable objects). It requires reflection and is very, very dangerous and should never ever be used unless you're actually interested in destroying the program.

1实际上,它可能的突变的字符串(和其他不可变的对象)。它需要反思并且非常非常危险,除非您真的有兴趣破坏程序,否则永远不要使用它。

回答by coobird

The object that strreferences can change, but the actual Stringobjects themselves cannot.

str引用的对象可以改变,但实际的String对象本身不能。

The Stringobjects containing the string "Hello"and "Help!"cannot change their values, hence they are immutable.

所述String对象包含字符串"Hello""Help!"不能改变它们的值,因此,它们是不可变的。

The immutability of Stringobjects does not mean that the references pointing to the object cannot change.

String对象的不变性并不意味着指向该对象的引用不能改变。

One way that one can prevent the strreference from changing is to declare it as final:

可以防止str引用更改的一种方法是将其声明为final

final String STR = "Hello";

Now, trying to assign another Stringto STRwill cause a compile error.

现在,尝试分配另一个StringtoSTR将导致编译错误。

回答by daveb

The string object that was first referenced by strwas not altered, all that you did was make strrefer to a new string object.

首先引用的字符串对象str没有改变,您所做的只是str引用一个新的字符串对象。

回答by akf

The String will not change, the reference to it will. You are confusing immutability with the concept of finalfields. If a field is declared as final, once it has been assigned, it cannot be reassigned.

String 不会改变,对它的引用会改变。您将不变性与final字段的概念混淆了。如果一个字段被声明为final,一旦它被分配,就不能重新分配。

回答by Preston Guillot

Immutability implies that the value of an instantiated object cannot change, you can never turn "Hello" into "Help!".

不变性意味着实例化对象的值不能改变,你永远不能把“Hello”变成“Help!”。

The variable str is a reference to an object, when you assign a new value to str you aren't changing the value of the object it references, you are referencing a different object.

变量 str 是对对象的引用,当您为 str 分配新值时,您并没有更改它引用的对象的值,而是引用了不同的对象。

回答by twolfe18

Though java tries to ignore it, stris nothing more than a pointer. This means that when you first write str = "Hello";, you create an object that strpoints to. When you reassign strby writing str = "Help!";, a new object is created and the old "Hello"object gets garbage collected whenever java feels like it.

尽管 java 试图忽略它,但它str只不过是一个指针。这意味着当您第一次写入时str = "Hello";,您创建了一个str指向的对象。当您str通过write 重新分配时str = "Help!";,会创建一个新对象,并且"Hello"只要 java 感觉它就会对旧对象进行垃圾收集。

回答by Michael Lloyd Lee mlk

Light_handle I recommend you take a read of Cup Size -- a story about variablesand Pass-by-Value Please (Cup Size continued). This will help a lot when reading the posts above.

Light_handle 我建议您阅读Cup Size - 一个关于变量值传递的故事(Cup Size 续)。这在阅读上面的帖子时会有很大帮助。

Have you read them? Yes. Good.

你读过它们吗?是的。好的。

String str = new String();

This creates a new "remote control" called "str" and sets that to the value new String()(or "").

这将创建一个名为“ str”的新“远程控制”并将其设置为值new String()(或"")。

e.g. in memory this creates:

例如在内存中这会创建:

str --- > ""


str  = "Hello";

This then changes the remote control "str" but does not modify the original string "".

这随后会更改遥控器“ str”,但不会修改原始字符串""

e.g. in memory this creates:

例如在内存中这会创建:

str -+   ""
     +-> "Hello"


str = "Help!";

This then changes the remote control "str" but does not modify the original string ""or the object that the remote control currently points to.

这随后会更改遥控器“ str”,但不会修改""遥控器当前指向的原始字符串或对象。

e.g. in memory this creates:

例如在内存中这会创建:

str -+   ""
     |   "Hello"
     +-> "Help!"

回答by user85421

Regarding the replace part of your question, try this:

关于您问题的替换部分,请尝试以下操作:

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

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

回答by martynas

For those wondering how to break String immutability in Java...

对于那些想知道如何打破 Java 中字符串不变性的人...

Code

代码

import java.lang.reflect.Field;

public class StringImmutability {
    public static void main(String[] args) {
        String str1 = "I am immutable";
        String str2 = str1;

        try {
            Class str1Class = str1.getClass();
            Field str1Field = str1Class.getDeclaredField("value");

            str1Field.setAccessible(true);
            char[] valueChars = (char[]) str1Field.get(str1);

            valueChars[5] = ' ';
            valueChars[6] = ' ';

            System.out.println(str1 == str2);
            System.out.println(str1);
            System.out.println(str2);           
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

    }
}

Output

输出

true
I am   mutable
I am   mutable

回答by Nayan Srivastava

In Java, objects are generally accessed by references. In your piece of code str is a reference which is first assigned to "Hello" (an automatic created object or fetched from constant pool) and then you assigned another object "Help!" to same reference. A point to note is the reference is the same and modified, but objects are different. One more thing in your code you accessed three objects,

在 Java 中,对象通常通过引用访问。在您的代码段中 str 是一个引用,它首先分配给“Hello”(自动创建的对象或从常量池中获取),然后您分配另一个对象“帮助!” 到相同的参考。需要注意的一点是引用是相同的和修改过的,但对象不同。在您访问三个对象的代码中还有一件事,

  1. When you called new String().
  2. When you assigned "hello".
  3. When you assigned "help!".
  1. 当您调用 new String() 时。
  2. 当你分配“你好”时。
  3. 当您分配“帮助!”时。

Calling new String() creates a new object even if it exists in string pool, so generally it should not be used. To put a string created from new String () into string pool you can try the intern()method.

调用 new String() 会创建一个新对象,即使它存在于字符串池中,所以一般不应该使用它。要将 new String() 创建的字符串放入字符串池中,您可以尝试该intern()方法。

I hope this helps.

我希望这有帮助。