字符串是不可变的。 究竟是什么意思?

这个问题在这里已经有了答案:

  • Java中字符串的不变性23回答

  • 在继续讨论不可变性的问题之前,我们先来看看String类及其功能,然后再做出结论。

    这是String工作原理:

    String str = "knowledge";
    

    像往常一样,这将创建一个包含"knowledge"的字符串,并为其分配一个引用str 。 够简单? 让我们执行一些更多的功能:

     String s = str;     // assigns a new reference to the same string "knowledge"
    

    让我们看看下面的语句是如何工作的:

      str = str.concat(" base");
    

    这附加一个字符串" base"str 。 但是等等,这是如何实现的,因为String对象是不可变的? 那么你的惊讶,它是。

    当执行上述语句时,虚拟机将获取String str的值,即"knowledge"并附加" base" ,给我们值"knowledge base" 。 现在,由于String是不可变的,VM不能将此值赋给str ,所以它创建一个新的String对象,给它一个值"knowledge base" ,并给它一个引用str

    这里需要注意的一点是,虽然String对象是不可变的,但它的引用变量不是。 所以这就是为什么在上面的例子中引用了一个新形成的String对象的原因。

    在上面的例子中,我们有两个String对象:第一个是我们用s指向的值"knowledge"创建s ,第二个是由str指向的"knowledge base" 。 但是,从技术上讲,我们有三个String对象,第三个是concat语句中的文字"base"

    关于字符串和内存使用的重要事实

    如果我们没有什么其他的参考s"knowledge" ? 我们会丢失那个String 。 但是,它仍然会存在,但由于没有引用而被认为丢失。 下面再看一个例子

    String s1 = "java";
    s1.concat(" rules");
    System.out.println("s1 refers to "+s1);  // Yes, s1 still refers to "java"
    

    发生了什么:

  • 第一行非常简单:创建一个新的String "java"并将s1引用它。
  • 接下来,VM创建另一个新的String "java rules" ,但没有任何指向它。 所以,第二个String会立即丢失。 我们无法达到它。
  • 引用变量s1仍然引用原始String "java"

    几乎每个应用于String对象以修改它的方法都会创建新的String对象。 那么,这些String对象在哪里去? 那么,这些都存在于内存中,任何编程语言的关键目标之一就是高效地使用内存。

    随着应用程序的增长, String文字占据大量内存很常见,甚至会导致冗余。 因此,为了使Java更高效, JVM将一个特殊的内存区域称为“字符串常量池”。

    当编译器看到一个String文字时,它会查找池中的String 。 如果找到匹配项,那么对新文字的引用将直接指向现有的String并且不会创建新的String对象。 现有的String只是多了一个参考。 这里有一点让String对象不可变:

    String常量池中,一个String对象可能有一个或多个引用。 如果多个引用指向相同的String而不知道它,如果其中一个引用修改了该String值,那将会很糟糕。 这就是为什么String对象是不可变的。

    那么,现在你可以说,如果有人重写了String类的功能呢? 这就是String类被标记为final的原因,所以没有人可以重写它的方法的行为。


    字符串是不可变的,意味着你不能改变对象本身,但你可以改变对象的引用。 当你叫a = "ty" ,实际上改变的参考a由字符串文字创造了一个新的对象"ty" 。 改变一个对象意味着使用它的方法来改变它的一个字段(或者这些字段是公开的而不是最终的,以便它们可以从外部更新而不用通过方法访问它们),例如:

    Foo x = new Foo("the field");
    x.setField("a new field");
    System.out.println(x.getField()); // prints "a new field"
    

    虽然在一个不可变的类中(声明为final,以防止通过继承进行修改)(其方法不能修改其字段,并且这些字段始终是私有的并建议是最终的),例如String,但不能更改当前的String,但是您可以返回一个新的String,即:

    String s = "some text";
    s.substring(0,4);
    System.out.println(s); // still printing "some text"
    String a = s.substring(0,4);
    System.out.println(a); // prints "some"
    

    你正在改变a指向什么。 尝试这个:

    String a="a";
    System.out.println("a 1-->"+a);
    String b=a;
    a="ty";
    System.out.println("a 2-->"+a);
    System.out.println("b  -->"+b);
    

    你会看到ab所指的对象没有改变。

    如果你想防止更改代码,对象a指,请尝试:

    final String a="a";
    
    链接地址: http://www.djcxy.com/p/20701.html

    上一篇: String is immutable. What exactly is the meaning?

    下一篇: Why can't I define a static method in a Java interface?