也說new
今天看到了Anytao的[你必須知道的.NET] 第五回:深入淺出關(guān)鍵字---把new說透。Anytao這一系列文章寫得都非常好,其實甚至正是我一直想寫的。比起各種應(yīng)用層面上的技巧,我更喜歡研究.NET的底層機制。但是光顧了自己研究了,也沒好好寫東西給大家分享。
《把new說透》這篇文章介紹的內(nèi)容不錯,但Anytao文字上可能沒有表達得很清晰。C# 2.0中關(guān)鍵字new有三種作用——1)作為修飾符覆蓋父類中的virtual成員,2)作為運算符創(chuàng)建對象,3)作為泛型類型中對類型形參的約束。
new的這三種功能其實是完全不相干的,Anders Liu個人感覺作為文章來說,應(yīng)該完全分開在不同的小節(jié)中去介紹。
1 new修飾符
new修飾符用于修飾類型成員(屬性、方法等)。
(懶得畫圖寫代碼了,所以采用純文字描述。大家可以看Anytao的代碼)
當(dāng)父類中編寫了virtual方法時,子類出現(xiàn)了相同簽名的方法時,必須冠以override或new運算符。
如果使用override運算符,則可以實現(xiàn)“多態(tài)”。即:將子類對象轉(zhuǎn)成父類型后,調(diào)用virtual方法,實際上執(zhí)行的是子類中的方法代碼。
而如果使用new運算符,則不會出現(xiàn)上述情況,將子類對象轉(zhuǎn)成父類型后,調(diào)用virtual方法,實際上執(zhí)行的是還是父類中的方法代碼。
2 new運算符
new運算符用于創(chuàng)建對象。當(dāng)使用new運算符創(chuàng)建對象時,會發(fā)生下列事情:
- 根據(jù)元數(shù)據(jù)中的類型信息,計算對象所需空間,根據(jù)值類型/引用類型的區(qū)別,在?;蛘叨阎虚_辟適當(dāng)大小的存儲區(qū)域。
- 根據(jù)元數(shù)據(jù)中的類型信息,對類成員空間進行排列。并初始化成員。(*)
- 調(diào)用構(gòu)造器。
- 返回對象引用。
所以,string s = new string("asdf");實際上是首先根據(jù)string類型信息在堆上開辟存儲空間,排列其成員,然后調(diào)用string(string s)簽名的構(gòu)造器,最后返回新對象引用,并通過等號賦給變量s。
因此,Anytao提到的int i與int i = new int()的區(qū)別也就出來了。
但這里Anytao沒有陳述清楚的是,int i出現(xiàn)的位置——int i即可以出現(xiàn)在類中,成為一個字段(域);也可以出現(xiàn)在方法中,成為一個變量(還有一種是出現(xiàn)在方法參數(shù)中,但就其語義,和變量是類似的)。
如果int i是一個字段(域)定義,那么兩者是沒有任何區(qū)別的。因為,注意上面第二條帶(*)的部分,當(dāng)客戶代碼初始化當(dāng)前類的對象時,會同時初始化這個i,將其值置為0。
如果int i是一個變量定義,那么,int i只是聲明了一個局部變量,此時的i不能直接使用,必須首先賦值(如果未賦值就使用,會得到一個編譯錯誤)。而int i = new int()則對i進行了一個初始化。
3 new約束
在泛型類型定義時,可以使用where指定一些約束,其中一種就是new約束。new 約束要求用作類型實參的類型必須帶有公共無參構(gòu)造器。如class A<T> where T : new();這里只有帶有公共無參構(gòu)造器的類型才能用作T。
需要注意兩點,1)如果同時存在其他約束,那么new約束應(yīng)該是最后一個。2)不能用new(int i)的形式來約束擁有指定簽名的構(gòu)造器。
好了,希望Anders Liu能給Anytao梳理一下文字。
浙公網(wǎng)安備 33010602011771號