Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java不可变字符串混淆_Java - Fatal编程技术网

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!谢谢你的提示。我应该在发布代码之前尝试一下。调整帖子以反映。