![](/img/trans.png)
[英]Abstract Factory design pattern to create objects? Why can’t we just use the new operator?
[英]Why don't we use new operator while initializing a string?
在一次采訪中有人問我這個問題:字符串是引用類型還是值類型。
我說它是參考類型。 然后他問我為什么在初始化字符串時不使用new運算符? 我說是因為c#語言具有用於創建字符串的更簡單的語法,並且編譯器自動將代碼轉換為對System.String類的構造函數的調用。
這個答案正確嗎?
字符串是不可變的引用類型。 ldstr IL指令允許將新的對象引用推送到字符串文字。 所以當你寫:
string a = "abc";
編譯器測試是否已在元數據中定義"abc"
文字,如果未聲明,則進行測試。 然后,它將代碼轉換為以下IL指令:
ldstr "abc"
這基本上使a
局部變量指向在元數據中定義的字符串文字。
所以我想說您的答案不太正確,因為編譯器沒有將其轉換為對構造函數的調用。
並非完全正確的答案。 字符串是“特殊”引用類型。 他們是一成不變的。 沒錯,編譯器在內部執行某些操作,但這不是構造函數調用。 它調用ldstr ,它將新的對象引用推送到存儲在元數據中的字符串文字。
示例C#代碼:
class Program
{
static void Main()
{
string str;
string initStr = "test";
}
}
這是IL代碼
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 8 (0x8)
.maxstack 1
.locals init ([0] string str,
[1] string initStr)
IL_0000: nop
IL_0001: ldstr "test"
IL_0006: stloc.1
IL_0007: ret
} // end of method Program::Main
您可以在上面看到ldstr
調用。
甚至由於Strings的不可改變性,僅保留唯一/唯一的字符串成為可能。 所有字符串都保存在哈希表中 ,其中鍵是字符串值,而值是對該字符串的引用。 每當我們有一個新的字符串CLR檢查時,哈希表中就已經有這樣的字符串了。 如果沒有,則不分配新的內存,並將引用設置為此現有字符串。
您可以運行以下代碼進行檢查:
class Program
{
static void Main()
{
string someString = "abc";
string otherString = "efg";
// will retun false
Console.WriteLine(Object.ReferenceEquals(someString, otherString));
someString = "efg";
// will return true
Console.WriteLine(Object.ReferenceEquals(someString, otherString));
}
}
好吧,編譯器具有簡化字符串創建的特殊語法是正確的。
關於編譯器生成對構造函數的調用的部分並不正確。 字符串文字是在應用程序啟動時創建的,因此在使用字符串文字的情況下,它只是對現有對象的引用的分配。
如果在循環中分配字符串文字:
string[] items = new string[10];
for (int i = 0; i < 10; i++) {
items[i] = "test";
}
它不會為每次迭代創建新的字符串對象,而只是將相同的引用復制到每個項目中。
關於字符串文字的其他兩點值得注意的事情是,編譯器不會創建重復項,並且如果您將它們連接起來,它將自動將它們合並。 如果您多次使用同一文字字符串,它將使用同一對象:
string a = "test";
string b = "test";
string c = "te" + "st";
變量a
, b
和c
都指向同一對象。
字符串類還具有可以使用的構造函數:
string[] items = new string[10];
for (int i = 0; i < 10; i++) {
items[i] = new String('*', 42);
}
在這種情況下,您實際上將獲得十個單獨的字符串對象。
不。 編譯器不會更改構造。 構造函數參數應為哪種類型? 串? ;-)
字符串文字是沒有名稱的常量。
此外,如果它支持運算符,則可以使用字符串文字初始化任何類:
public class UnitTest1 {
class MyStringable {
public static implicit operator MyStringable(string value) {
return new MyStringable();
}
}
[TestMethod]
public void MyTestMethod() {
MyStringable foo = "abc";
}
}
采取以下測試方法:
[TestClass]
class MyClass {
[TestMethod]
public void MyTest() {
string myString = "foo";
if (myString == "bar")
Console.WriteLine("w00t");
}
}
創建以下IL代碼:
.method public hidebysig instance void MyTest() cil managed
{
.custom instance void [Microsoft.VisualStudio.QualityTools.UnitTestFramework]Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute::.ctor()
.maxstack 2
.locals init (
[0] string myString,
[1] bool CS$4$0000)
L_0000: nop
L_0001: ldstr "foo"
L_0006: stloc.0
L_0007: ldloc.0
L_0008: ldstr "bar"
L_000d: call bool [mscorlib]System.String::op_Equality(string, string)
L_0012: ldc.i4.0
L_0013: ceq
L_0015: stloc.1
L_0016: ldloc.1
L_0017: brtrue.s L_0024
L_0019: ldstr "w00t"
L_001e: call void [mscorlib]System.Console::WriteLine(string)
L_0023: nop
L_0024: ret
}
如您所見,所有字符串值(foo,bar和w00t)仍然是字符串,並且不會調用任何隱藏的構造函數。
希望這能進一步解釋。
眾所周知,字符串是不可變的,因此沒有隱式的構造函數調用。 我想為您添加以下參考,這可能會使您更加了解:
但是我們可以在初始化字符串時使用new運算符
String str = new char[] {'s','t','r'};
這個答案正確嗎?
不,字符串被緩存和使用,可以像在IL中那樣說。
這是我的看法,我不太確定,因此請以一小撮鹽回答我。
.NET中的字符串文字是獨立的,其長度或其他數據結構內部包含在文字值本身中。 因此,與C不同,在.NET中分配字符串文字只是分配字符串整個數據結構的內存地址的問題。 在C語言中,我們需要使用new in string類,因為它需要圍繞以null終止的字符串(例如,長度)分配其他數據結構。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.