字符串在 C# 中是如何工作的? [关闭]

Posted

技术标签:

【中文标题】字符串在 C# 中是如何工作的? [关闭]【英文标题】:How does string works in c#? [closed] 【发布时间】:2016-12-12 04:47:46 【问题描述】:

我知道字符串是不可变的,一旦创建我们就无法更改它,我读过如果我们创建一个新的字符串对象并为其分配一个值,然后我们在内部为同一个字符串对象分配另一个值实际上存在创建并分配了新值的另一个对象。假设我有:

string str = "dog";            
str =  "cat";  

如果我写Console.WriteLine(str);,它会返回cat。 那么内部有两个对象?但是他们有相同的名字吗?它是如何工作的?我已经对谷歌进行了一些研究,但我还没有找到足以让我信服的东西,所以我可以澄清我对此的想法。 我知道字符串是引用类型,所以我们在堆栈中有一个对象引用了堆中的一个值,在这种情况下发生了什么?(参见上面的代码)。

我已经上传了一张图片,如果我对堆栈和堆的概念有误,请向我道歉,这就是我问这个问题的原因。 图片是否反映了第一行代码(string str = "dog";)中发生的情况?然后第二行代码应该发生什么?堆中的dog 值发生了变化?然后在堆栈中创建一个引用它的新对象?那么之前存在的对象会发生什么?他们有相同的名字吗? 很抱歉有这么多问题,但我认为正确理解这一点并了解幕后发生的事情非常重要...

【问题讨论】:

【参考方案1】:

当您将str 分配给“dog”时,它会按照您在内存中的描述进行:引用变量str 现在“指向”您刚刚实例化的字符串的位置。

str => MEMORY LOCATION "1": "dog"
       MEMORY LOCATION "2":
       MEMORY LOCATION "3":

str 重新分配给您的新字符串“cat”时,它也会在内存中创建,现在str 已调整为指向新位置的“cat”。

       MEMORY LOCATION "1": "dog"
str => MEMORY LOCATION "2": "cat"
       MEMORY LOCATION "3":

“狗”会怎样?现在它实际上是不可访问的,因为我们不再引用它的位置(在内存、堆中,术语在这种情况下是可以互换的)。稍后,当垃圾收集器检查内存进行清理时,它会意识到没有任何引用“狗”,它会根据需要将内存标记为删除和替换。

【讨论】:

【参考方案2】:

你已经接近了。您的图片准确地代表了第一行代码中发生的事情。但是,情况与您描述的第二行代码略有不同。

对于str = "cat"; 行,在堆中创建第二个字符串对象,并更改str 变量以引用该新对象。剩下的 str 指向 "cat" 和一个孤立的 "dog" 对象在堆上没有对其的引用。

"dog" 对象可能会被垃圾收集器清理掉,因为没有对它的引用。

【讨论】:

【参考方案3】:

查看String Interning 或.Net String Intern table 或CLR Intern Pool。 基本上,公共语言运行时 (CLR) 维护一个 [唯一] 字符串值表,每当您在代码中操作字符串时,CLR 都会检查此实习表以查看您尝试创建的新值是否已经存在或不。如果是,它只是重新分配您正在修改的变量以指向实习池中的该条目。如果不是,它将值添加到池中并返回该新引用。池中不再被变量引用的旧值被垃圾回收。

【讨论】:

我很难选择答案,因为您的所有答案都非常具有描述性,我现在已经澄清了这件事,谢谢!!! 这个答案是完全错误的。字符串仅在编译时被隐式实习。在运行时,仅当代码通过调用string.Intern() 方法显式 请求字符串时,才会对字符串进行实习。此外,一旦进入实习池,string 对象就永远被垃圾回收。他们无限期地留在那里。实习生池不是缓存,它主要是放置编译代码时找到的字符串文字的地方。【参考方案4】:

是的,有两个对象。不,他们没有相同的名字。尽量不要将变量视为对象本身的“名称”本身 - 它更像是对象在内存中的位置的临时名称。 (将变量视为对象的“名称”有点误导的原因是您可以有多个变量引用同一个对象;对象本身并没有多个“名称”,或者是几个对象 - 这就是您存储引用的方式)。

“string str”最初引用了字符串“dog”。将“cat”分配给“str”后,该变量现在具有对字符串“cat”的引用。

这两个字符串仍然存在于内存中(至少暂时如此),但“dog”字符串不再可访问,因为您没有对它的引用(因此不再“知道”它的位置)。你不知道它们会在内存中存在多久,因为垃圾收集器可以随时从内存中删除“狗”字符串,因为不再有任何对它的引用。

顺便说一句,您对堆栈上的值以及对堆上对象的引用是正确的 - 这是一个很好的区别。

【讨论】:

以上是关于字符串在 C# 中是如何工作的? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

符号:隐式字符串转换在 JavaScript 中是如何工作的?

如何在一行上显示字符串 x 次 C# [关闭]

next() 在这个 python 代码中是如何工作的

在 c# 中将时间字符串转换为不同的 DateTime 格式 [关闭]

排序函数在 C++ 算法中是如何工作的,以及如何改进这段代码? [关闭]

C# 检查对象和字符串的最佳实践 [关闭]