String is immutable. What exactly is the meaning?
我在不可变字符串上编写了以下代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
输出:
1 2 | a 1-->a a 2-->ty |
这里,变量
来源:https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
在进一步讨论不可变性之前,让我们先看一下
这就是
1 |
与往常一样,这会创建一个包含
1 |
让我们看看下面的语句是如何工作的:
1 | str = str.concat(" base"); |
这会将字符串
执行上述语句时,vm取
这里需要注意的一点是,虽然
在上面的例子中,我们有两个
如果我们没有另一个参考
1 2 3 |
发生了什么事:
参考变量
几乎每一种方法,应用于
随着应用程序的增长,
当编译器看到
在
好吧,现在你可以说,如果有人覆盖了
字符串是不可变的,意味着不能更改对象本身,但可以更改对对象的引用。
执行
更改对象意味着使用其方法更改其某个字段(或者字段是公共的,不是最终的,这样可以从外部更新它们,而无需通过方法访问它们),例如:
1 2 3 | Foo x = new Foo("the field"); x.setField("a new field"); System.out.println(x.getField()); // prints"a new field" |
在不可变类(声明为final,以防止通过继承进行修改)中(其方法不能修改其字段,而且字段始终是私有的,建议为final),例如string,不能更改当前字符串,但可以返回新字符串,即:
1 2 3 4 5 |
你在改变
1 2 3 4 5 6 |
您将看到,
如果要防止代码更改
1 |
字符串是包含一系列utf-16代码单元的
例如。
1 | String s |
它为字符串引用创建空间。分配会复制周围的引用,但不会修改这些引用所引用的对象。
你也应该知道
1 |
没有什么有用的。它只创建另一个实例,由与
Java双引号字符串(如EDCOX1×28)实际上是对接口EDCOX1和17个实例的引用,所以EDCOX1×30 }是对同一个字符串实例的引用,而不管它在代码中出现了多少次。
"hello"创建一个集合实例,而
不可变意味着不能更改同一引用的值。每次需要创建新引用时,都意味着新的内存位置。前任:
1 2 |
在这里,在上面的代码中,内存中有两个块用于存储值。第一个块用于值"abc",第二个块用于值"bcd"。第二个值不替换为第一个值。
这就是所谓的不变。
看到这里
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class ImmutableStrings { public static void main(String[] args) { testmethod(); } private static void testmethod() { String a="a"; System.out.println("a 1-->"+a); System.out.println("a 1 address-->"+a.hashCode()); a ="ty"; System.out.println("a 2-->"+a); System.out.println("a 2 address-->"+a.hashCode()); } } |
输出:
1 2 3 4 | a 1-->a a 1 address-->97 a 2-->ty a 2 address-->3717 |
这表示每当修改不可变字符串对象
在您的示例中,变量
您没有在赋值语句中更改对象,而是将一个不可变对象替换为另一个不可变对象。对象
相反,
1 2 3 4 | StringBuffer b = new StringBuffer("Hello"); System.out.writeln(b); b.append(", world!"); System.out.writeln(b); |
这里,您没有重新分配
实际上,您正在获取对一个新字符串的引用,因为该字符串本身是不可变的,所以不会被更改。这是相关的。
见
维基百科上的不变对象
不可变对象是在创建后其状态不能修改的对象。
所以
一旦分配了一个字符串对象,该对象就不能在内存中更改。
总之,您所做的就是将"a"的引用更改为新的字符串对象。
1 2 3 4 5 |
这表明一旦创建了一个字符串对象,就不能更改它。每次需要创建新的并放入另一个字符串时。S
我认为以下代码可以消除差异:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | String A = new String("Venugopal"); String B = A; A = A +"mitul"; System.out.println("A is" + A); System.out.println("B is" + B); StringBuffer SA = new StringBuffer("Venugopal"); StringBuffer SB = SA; SA = SA.append("mitul"); System.out.println("SA is" + SA); System.out.println("SB is" + SB); |
JavaEDCX1 0Ω是不可变的,EDCOX1×0将以对象的形式存储值。因此,如果u指定值
也许上面提供的每个答案都是对的,但我的答案是具体使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | public class ImmutabilityTest { private String changingRef ="TEST_STRING"; public static void main(String a[]) { ImmutabilityTest dn = new ImmutabilityTest(); System.out.println("ChangingRef for TEST_STRING OLD :" + dn.changingRef.hashCode()); dn.changingRef ="NEW_TEST_STRING"; System.out.println("ChangingRef for NEW_TEST_STRING :" + dn.changingRef.hashCode()); dn.changingRef ="TEST_STRING"; System.out.println("ChangingRef for TEST_STRING BACK :" + dn.changingRef.hashCode()); dn.changingRef ="NEW_TEST_STRING"; System.out.println("ChangingRef for NEW_TEST_STRING BACK :" + dn.changingRef.hashCode()); String str = new String("STRING1"); System.out.println("String Class STRING1 :" + str.hashCode()); str = new String("STRING2"); System.out.println("String Class STRING2 :" + str.hashCode()); str = new String("STRING1"); System.out.println("String Class STRING1 BACK :" + str.hashCode()); str = new String("STRING2"); System.out.println("String Class STRING2 BACK :" + str.hashCode()); } } |
产量
1 2 3 4 5 6 7 8 | ChangingRef for TEST_STRING OLD : 247540830 ChangingRef for NEW_TEST_STRING : 970356767 ChangingRef for TEST_STRING BACK : 247540830 ChangingRef for NEW_TEST_STRING BACK : 970356767 String Class STRING1 : -1163776448 String Class STRING2 : -1163776447 String Class STRING1 BACK : -1163776448 String Class STRING2 BACK : -1163776447 |
在您的示例中,
1 2 3 4 |
打印"A",因为我们从未对
只有引用正在更改。首先,
希望下面的代码可以澄清您的疑问:
1 2 3 4 5 6 7 8 9 10 | public static void testString() { String str ="Hello"; System.out.println("Before String Concat:"+str); str.concat("World"); System.out.println("After String Concat:"+str); StringBuffer sb = new StringBuffer("Hello"); System.out.println("Before StringBuffer Append:"+sb); sb.append("World"); System.out.println("After StringBuffer Append:"+sb); } |
字符串concat之前:你好字符串concat之后:你好在StringBuffer追加之前:您好在stringbuffer append:helloworld之后
字符串是不可变的,这意味着一旦创建字符串对象,它的内容就不能更改。如果要修改内容,则可以使用StringBuffer/StringBuilder而不是String。StringBuffer和StringBuilder是可变类。
如果某个对象