字符串是值类型还是引用类型?
Posted
技术标签:
【中文标题】字符串是值类型还是引用类型?【英文标题】:Is string a value type or a reference type? 【发布时间】:2010-11-07 08:04:58 【问题描述】:我只是找不到一个“好的”解释......
【问题讨论】:
相关***.com/questions/636932/… 接受的答案“证明”它是一个引用类型。与其他引用类型不同,它在以下评估时不会抛出NullReferenceException
:string s0 = null; Console.WriteLine(s0); string result = String.Concat(s0, "aaa");
也许它只是不完全适合公认的类别。
@H2ONaCl 不期望在这些情况下抛出该异常;方法可以选择抛出ArgumentNullException
,但两种方法明确表示它们不选择这样做; Console.WriteLine
说:“如果 value 为 null,则仅将行终止符写入标准输出流。”; String.Concat
表示“使用空字符串代替任何空参数。”。这很好。我们通常期望NullReferenceException
的唯一时间是s0.Length
之类的东西:确实,抛出了
【参考方案1】:
Console.WriteLine(typeof(string).IsClass); // true
这是一个引用类型。
它不能是值类型,因为值类型需要已知的堆栈大小等。作为引用类型,引用的大小是预先知道的,甚至如果字符串的大小不是。
它表现就像你期望值类型表现一样,因为它是不可变的;即它一旦创建就不会*改变。但是还有很多其他不可变的引用类型。例如,委托实例。
*=StringBuilder
内部除外,但在它执行此操作时您永远看不到它...
【讨论】:
+1。我真的不喜欢小写字符串“type”。看起来像值类型,行为像引用类型。 这个案子和它有什么关系?它只是一个别名......例如,对象是引用类型。 StringBuilder 在内部使用 char[],而不是字符串。 @Phong 再次检查。上次我查看时,它确实是一个string
- 然后它会进行不安全的变异(分配一个新字符串并在需要时进行复制)。你检查过吗?如果是这样:什么 .net 版本?
@SMI string
的默认值是null
,正是因为string
是一个引用类型。说string
的默认值为""
是不正确的,因为:它不是。【参考方案2】:
String 是不可变的引用类型。
请参阅关于不变性的博文 Immutable types: understand their benefits and use them。
【讨论】:
【参考方案3】:String is a reference type.
【讨论】:
【参考方案4】:基本的“解释”是基于“什么”实际存储在您“声明”事物的变量时分配的内存位置。如果事物的实际值存储在变量名所指的内存位置,那么它就是值类型。
int x; // memory allocated to hold Value of x, default value assigned of zero
如果,otoh,当你“声明”变量时分配的内存槽将只保存一些 other 存储实际值(或值)的内存地址,那么它是一个引用类型.
MyClass x; // Memory allocated to hold an address,
// default address of null (0) assigned.
// NO MEMORY ALLOCATED for x itself
或者,如果声明包括初始化,
MyClass x = new MyClass();
// Now, Memory slot (call it Addr1) is allocated to hold address of x,
// more memory (call it Addr2) is allocated to hold a new MyClass object.
// New MyClass object created, stored in memory Addr2 (on the Heap)
// Address of new object (Addr2) is stored in Addr1
对于字符串,字符串是在堆上创建的,它的地址在为变量分配的内存槽中,所以它是一个引用类型。
【讨论】:
【参考方案5】:String 是一种不可变的引用类型,它具有某些特性,使其偶尔看起来是一个值类型
【讨论】:
【参考方案6】:字符串类型表示零个或多个 Unicode 字符的序列。 string 是 .NET Framework 中 String 的别名。
虽然字符串是引用类型,但定义相等运算符(== 和 !=)是为了比较字符串对象的值,而不是引用。这使得对字符串相等性的测试更加直观。例如:
string a = "hello";
string b = "h";
// Append to contents of 'b'
b += "ello";
Console.WriteLine(a == b);
Console.WriteLine((object)a == (object)b);
这会显示“True”,然后显示“False”,因为字符串的内容是等价的,但是 a 和 b 不引用同一个字符串实例。
字符串是不可变的——字符串对象的内容在对象创建后不能更改,尽管语法看起来好像您可以这样做。例如,当您编写此代码时,编译器实际上会创建一个新的字符串对象来保存新的字符序列,并将该新对象分配给 b。然后字符串“h”就可以进行垃圾回收了。
string b = "h";
b += "ello";
【讨论】:
【参考方案7】:在许多语言中,有两种一般类型的事物:定义类型的存储位置将实际保存该类型的对象,以及定义类型的存储位置将保存对对象的引用存储在其他地方的那种类型。事物还可能提供多种类型的语义:
-
不可变的值语义:特定类型的实例具有构成身份基础的某些特征(“值”)。值相等的两个项目可以互换使用,而不管它们存储在哪里。只要实例存在,该值就会保持不变。这种类型的变量可能会改变其值,但只能通过将不同的实例存储到变量中。
不可变引用语义:通常类似于不可变值语义,除了在不同时间创建的两个实例将报告自己是不同的实例。
可变值语义:特定类型的实例具有构成身份基础的某些特征或特征集合(“值”),但这些特征可以在不替换整个实例的情况下更改。每个实例都存储在一个变量或字段中;将一个变量或字段复制到另一个将所有值从第一个实例复制到第二个实例,但实例保持独立。未来对一个实例的更改不会影响另一个。
可变引用语义:每个实例都与自身相同,但与其他实体不同,并且实例具有一个或多个值,这些值可以在现有实例中更改。任意数量的变量或字段都可以包含对任何实例的引用。将一个或字段变量复制到另一个只会使第二个引用与第一个相同的实例。因此,对其中一个变量引用的实例的任何更改都会影响另一个变量引用的实例(即同一个实例)。
在某些编程语言(如 C++)中,直接存储和间接引用类型都可以实现上述四种语义类型中的任何一种。在 .net 和 C# 中,具有暴露字段的直接存储类型始终实现#3,具有暴露字段的类类型始终实现#4,其他值类型可以实现上述任何一种,其他引用类型可以实现#1、#2、或#4,但不是#3,只有轻微泄漏的抽象。字符串实现#1。
【讨论】:
【参考方案8】:也许文章 Strings in .NET and C# 可以帮助你。根据这篇文章,字符串是一种引用类型。
【讨论】:
以上是关于字符串是值类型还是引用类型?的主要内容,如果未能解决你的问题,请参考以下文章