Java不可变字符串混淆
如果Java不可变字符串混淆,java,Java,如果Strings在Java中是不可变的,那么我们如何编写为: String s = new String(); s = s + "abc"; 字符串是不可变的。 这意味着String的实例不能更改 您正在更改s变量以引用不同(但仍然不可变)的String实例 String s = new String(); 创建一个新的、不可变的空字符串,变量“s”引用它 s = s+"abc"; 创建一个新的、不可变的字符串;空字符串和“abc”、变量“s”
String
s在Java中是不可变的,那么我们如何编写为:
String s = new String();
s = s + "abc";
字符串是不可变的。这意味着
String
的实例不能更改
您正在更改s
变量以引用不同(但仍然不可变)的String
实例
String s = new String();
创建一个新的、不可变的空字符串,变量“s”引用它
s = s+"abc";
创建一个新的、不可变的字符串;空字符串和“abc”、变量“s”的串联现在引用这个新对象。不可变类是那些其方法可以更改其字段的类,例如:
Foo f = new Foo("a");
f.setField("b"); // Now, you are changing the field of class Foo
String s = "Hello";
s.substring(0,1); // s is still "Hello"
s = s.substring(0,1); // s is now referring to another object whose value is "H"
但在不可变类(例如String)中,一旦创建对象,就不能更改它,但当然,可以将引用重新分配给另一个对象。例如:
Foo f = new Foo("a");
f.setField("b"); // Now, you are changing the field of class Foo
String s = "Hello";
s.substring(0,1); // s is still "Hello"
s = s.substring(0,1); // s is now referring to another object whose value is "H"
只是想澄清一下,当你说s=s+“abc”; 这意味着,创建一个新的字符串实例(由s和“abc”组成),然后将该新字符串实例分配给s。因此,s中的新引用与旧引用不同
记住,变量实际上是对某个特定内存位置的对象的引用。该位置的对象保持在该位置,即使您更改变量以引用不同位置的新对象。第一个答案绝对正确。你应该把它标记为已回答
s=s+“abc”
不会附加到s对象。它创建一个新字符串,其中包含s对象(其中没有)和“abc”中的字符
如果字符串是可变的。它将具有append()等方法以及StringBuilder和StringBuffer上的其他此类变异方法
Josh Bloch的高效Java对不可变对象及其值进行了出色的讨论。您的字符串变量不是字符串。它是对字符串实例的引用 你自己看看:
String str=“测试字符串”;
System.out.println(System.identityHashCode(str));//字符串的实例ID
str=str+“另一个值”;
System.out.println(System.identityHashCode(str));//哇,这是另一根弦!
str变量指向的实例是不可变的,但该变量可以指向所需字符串的任何实例
如果不希望重新分配str以指向其他字符串实例,请将其声明为final:
final String str=“测试字符串”;
System.out.println(System.identityHashCode(str));//字符串的实例ID
str=str+“另一个值”;//坏得可怕
将创建一个空的字符串
对象(“”
)。变量s
引用该对象
s = s + "abc";
“abc”
是一个字符串文本(它只是一个字符串
对象,隐式创建并保存在字符串池中),因此可以重用它(因为字符串是不可变的,因此是常量)。但是当您执行new String()
时,情况就完全不同了,因为您是显式创建对象的,因此不会在池中结束。你可以通过一种叫做“实习”的方式把它扔进游泳池
因此,
s+“abc”
,因为此时,空字符串(“
)和“abc”
的串联并不能真正创建一个新的字符串
对象,因为最终结果是池中已经存在的“abc”
。因此,最后变量s
将引用池中的文字“abc”
。我相信你们都在使这个问题变得比需要的复杂得多,这只会让那些试图学习的人感到困惑
在Java中使对象不可变的主要好处是,它可以通过引用传递(例如,传递到另一个方法或使用赋值运算符赋值),而不必担心对象的下游更改会导致当前方法或上下文中的问题。(这与任何关于对象线程安全性的对话都大不相同。)
举例来说,创建一个将字符串作为参数传递给单独方法的应用程序,并在该方法中修改该字符串。打印被调用方法末尾的字符串,然后在控件返回调用方法之后打印。字符串将具有不同的值,这是因为它们指向不同的内存位置,这是“更改”不可变字符串(创建新指针并在幕后将其指向新值)的直接结果。然后创建一个应用程序,除了使用StringBuffer(它不是不可变的)之外,它执行相同的操作。(例如,您可以附加到StringBuffer来修改它。)打印的StringBuffers将具有相同的值,这是因为它(a)通过引用传递,就像Java将所有对象作为参数传递给方法一样,(b)是可变的
我希望这能帮助那些正在阅读这篇文章并试图学习的人 s不是字符串,它是一个容器,其中包含对字符串的引用。首先,它保存对new string()返回的字符串的引用,然后将其更改为保存由new string()+“abc”返回的字符串的引用,即对另一个string.Simple的引用。str.toString()返回。。。绳子。调用((Object)str.toString()会为我们提供实际的实例ID。这是为了演示。不,不是。Java中的方法是虚拟的,将对象强制转换为超级类型在这里没有效果。
字符串
的重写toString()
方法实现仍将被调用。您需要调用System.identityHashCode(str)
,以获取对象的原始基于身份的hashCode.Argh!谢谢你的提示。我应该在发布代码之前尝试一下。调整帖子以反映。