当两者都是引用类型时,字符串与类
这是我上一次采访的方式:
问题:字符串存储在哪里?
答:堆是因为它是参考类型
问题:请解释以下代码:
static void Main(string[] args) { string one = "test"; string two = one; one = one + " string"; Console.WriteLine("One is {0}" , one); Console.WriteLine("Two is {0}", two); }
答案:画了两张如下图:
(代表声明, string two = one;
(表示语句, one = one + " string";
;.在堆上创建一个新字符串并分配)
问题:正确。 为下面的代码片段绘制类似的内容:
class Program { static void Main(string[] args) { Test one = new Test { someString = "test" }; Test two = one; one.someString = "test String"; Console.WriteLine("One is {0}", one.someString); Console.WriteLine("Two is {0}", two.someString); } } class Test { public string someString { get; set; } }
回答:
[ Test two = one
]
one.someString = "test String";
问题:好的。 你说过strings
和classes
都是引用类型。 那么为什么创建一个新的字符串对象并赋值,而对于类,现有的字符串属性本身会被修改?
答案:因为字符串是不可变的,而类是可变的。
(虽然我清除了采访,但我仍然不理解这种行为。为什么类的设计者在保持字符串不可变的同时使它变得可变?到处都有很多热情的答案,但任何人都可以通过解释这种特殊的行为来简化它用上面的代码?)
其中一个原因是字符串是不可变的,即使它们是引用类型,也是为了使它们看起来和行为像原始类型(例如,int,double,float)。
这也是字符串是唯一可以表示为文字的引用类型(例如, "some string"
)的原因。 许多其他语言采用相同的方法,例如Java。
字符串是不可变的,因为从逻辑上讲,它们是单个值,并且可变性会导致许多意外行为。
但是,字符串不是值类型 ,因为它们往往会传递很多,这需要大量复制值。 这将变得非常昂贵,特别是对于大型琴弦。
因此,为了充分利用这两个世界,.Net中的字符串是引用类型,但也是不可变的。
命令one = ...
将名为 one
的* 指针设置为新值。 由于two
是不同的指针,因此它保留了原始值。
命令one.someString = ...
修改一个引用的对象 。 two
仍然是一个不同的指针,但由于它指向同一个对象,因此修改在它们之间共享。
字符串共享缓冲区。 在你的情况下,如果一个和两个是字符串,它们将是单独的对象(堆上的两个对象),但在内部它们将指向相同的缓冲区(堆上的第三个对象)。