我在不可变字符串上写了下面的代码。

public class ImmutableStrings {

    public static void main(String[] args) {
        testmethod();
    }

    private static void testmethod() {
        String a = "a";
        System.out.println("a 1-->" + a);
        a = "ty";
        System.out.println("a 2-->" + a);
    }
}

输出:

a 1-->a  
a 2-->ty

这里变量a的值被改变了(尽管许多人说不可变对象的内容不能被改变)。但是说字符串是不可变的到底是什么意思呢?你能给我解释一下这个话题吗?

来源:https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html


当前回答

在你的例子中,a首先指向“a”,然后指向“ty”。你没有改变任何String实例;你只是改变了a引用的String实例。例如,这个:

String a = "a";
String b = a; // b refers to the same String as a
a = "b"; // a now refers to a different instance
System.out.println(b);

打印"a",因为我们从未改变b所指向的String实例。

其他回答

不可变意味着你不能不改变同一个引用的值。每次你需要创建新的引用就意味着新的内存位置。 例:

String str="abc";
str="bcd";

在上面的代码中,内存中有2个块用于存储值。第一个表示“abc”,第二个表示“bcd”。第二个值不替换第一个值。

这叫做不可变。

不可变对象是创建后状态不能修改的对象。

a = "ABC" <——immutable object。"a"保存对对象的引用。 并且,a = "DEF" <——另一个不可变对象,"a"现在保存着对它的引用。

一旦你分配了一个字符串对象,该对象就不能在内存中被改变。

总之,您所做的就是将“a”的引用更改为一个新的字符串对象。

If some object bar holds a reference to a mutable object foo and encapsulates some of its state in mutable aspects of foo's state, that will allow code which can change those aspects of foo to change the corresponding aspects of bar's state without actually touching bar or even knowing of its existence. Generally, this means that objects which encapsulate their own state using mutable objects must ensure that no references to those objects are exposed to any code which might unexpectedly mutate them. By contrast, if bar holds a reference to an object moo and only uses immutable aspects of moo other than identity to encapsulate its state, then bar can freely expose moo to outside code without worrying about anything the outside code might do to it.

字符串是一个char[],包含一系列UTF-16代码单元,该数组的int偏移量和int长度。

为例。

String s

它为字符串引用创建空间。赋值复制周围的引用,但不修改这些引用所引用的对象。

你也应该意识到

new String(s)

并没有做任何有用的事情。它只是创建了另一个实例,支持的数组、偏移量和长度与s相同。很少有理由这样做,因此大多数Java程序员认为这是一种糟糕的做法。

Java双引号字符串,如“my string”,实际上是对内部string实例的引用,因此“bar”是对同一个string实例的引用,而不管它在代码中出现了多少次。


“hello”创建了一个被池化的实例,而新的String(…)创建了一个非池化的实例。尝试system . out。println((“hello”= =“你好 ") + "," + ( 新的字符串“hello”= =“你好 ") + "," + ( 新的字符串(“hello”)= =新的字符串(“hello”)));你应该看到真,假,假

你实际上得到了一个新字符串的引用,字符串本身没有被改变,因为它是不可变的。这是相关的。

See

维基百科上的不可变对象