標籤:
一、new的準系統
一般說來,new關鍵字在.net中用於以下四個場合。
- 作為運算子,用於建立對象和調用建構函式,範圍用得最多吧。
- 實現多態。
- 作為修飾符,用於向基類成員隱藏繼承類成員,一般繼承情況下,擴充基類方法用得多。
- 作為泛型參數約束,用於在泛型聲明中約束用作型別參數的參數類型,這個也好像用得多吧。
二、new的基本用法
- 先來說說作為泛型參數約束的用法。
MSDN 中的定義是:new約束指定泛型類聲明中的任何型別參數都必須有公用的無參建構函式。當泛型型別建立類型的新執行個體時,將此約束應用於型別參數。有個注意的地方就是有其他約束時,new約束比須最後指定。下面實現一個例子:1 class Person<T> where T : new()
2 {
3 public T GetName()
4 {
5 return new T();
6 }
7 }
8
9 class Boy
10 {
11 private string _name;
12
13 public string Name
14 {
15 get{return _name;}
16 set { _name = value; }
17 }
18
19 public Boy()
20 {
21 _name = "feng";
22 }
23 }
24
25 class Program
26 {
27 static void Main(string[] args)
28 {
29 Person<Boy> MBoy = new Person<Boy>();
30
31 Boy a = new Boy();
32 Console.WriteLine(a.Name);
33
34 Console.WriteLine(MBoy.GetName().Name);
35 Console.ReadKey();
36 }
37 }
結果 列印出2個"feng"
2. 再來說說作為修飾符和多態的用法。
作為修飾符,主要用在向基類成員隱藏繼承成員。如果要實現衍生類別隱藏方法,則基類的方法必須定義為virtual,將基類方法實現為virtual可以保證向前擴充和向後相容。分別在衍生類別通過override或new進行靈活控制。new和overdide不可同時共存,因為new用於建立一個新成員,同時隱藏基類的同名成員,注意不是覆蓋,要想訪問基類的成員可以通過base修飾符來訪問。而override則不行。
通過new實現多態。
- 比如通過基類擴充來實現繼承式多態:
Animal a =new dog();
//其中cry()方法實現為虛方法,子類dog繼承至Animal 並覆寫了該方法,雖然a是父類Animal的一個變數,但是實現的是子類dog的方法,這正是new實現多態的體現吧。
a.cry();
2.也可以通過繼承介面來實現多態:
IAnimalRun r=new dog();//dog實現了介面IAnimalRun 的 run()方法
r.run();
看下面一個例子來加深理解:
1 class Num
2 {
3 public static int i = 111;
4
5 public virtual void ShowClassInfo()
6 {
7 Console.WriteLine("我是基類呵呵");
8 }
9 public virtual void ShowNum()
10 {
11 Console.WriteLine("基類的數字是{0}", i.ToString());
12 }
13 }
14
15 class SubNum : Num
16 {
17 new public static int i = 222;
18
19 //new 作為修飾符:只是隱藏基類同名方法
20 public new virtual void ShowClassInfo()
21 {
22 Console.WriteLine("我是子類哈哈");
23 }
24
25 //override則是覆寫了基類的方法
26 public override void ShowNum()
27 {
28 Console.WriteLine("子類的數字是{0}", i.ToString());
29 }
30 }
31
32 class Program
33 {
34 static void Main(string[] args)
35 {
36 Num num1 = new Num();//new 運算子用法
37 num1.ShowNum();
38 SubNum sbnum = new SubNum();
39 //下面2個調用的都是子類的方法 但是實現機制不一樣
40 sbnum.ShowNum();//結果:111
41
42 sbnum.ShowClassInfo();//結果:我是子類
43
44 //new作為多態的用法:下面是典型的基類繼承似多態
45 Num num2 = new SubNum();//num2雖然是基類的變數,但是指向了之類SubNum執行個體的引用
46
47 //調用方法時會在運行期檢查虛擬方法表,來確定要調用的方法
48 num2.ShowClassInfo();//由於方法只是被隱藏了,沒有被重寫 所有還是調用的基類的方法
49
50 num2.ShowNum();//方法被覆蓋了 所有調用的是子類的方法
51 Console.ReadKey();
52 }
53 }
個人覺得new實現多態可以放到作為運算子裡面不去,不知道你們是不是這樣認為的。
3.作為運算子的用法。
作為修飾符和約束的情況也許要多加理解,作為運算子一定是一個不難理解的話題,因為大多數時候我們就是用new作為運算子來建立對象或結構體或枚舉等等。new運算子用於返回一個引用,指向系統分配的託管堆的記憶體位址,那new執行個體化實值型別和參考型別有啥區別呢,來看一段簡單的代碼。
class MyClass
2 {
3 private int _id;
4 public MyClass(int id)
5 {
6 _id = id;
7 }
8 }
9
10 struct MyStruct
11 {
12 private string _name;
13 public MyStruct(string name)
14 {
15 _name = name;
16 }
17 }
18
19 class Program
20 {
21 public static void Main()
22 {
23 int i=0;
24 int j = new int();
25 string str = new string(‘#‘, 10);
26
27 MyClass myClass = new MyClass(123);
28
29 MyStruct myStruct = new MyStruct("hehe");
30
31 Console.WriteLine(j);
32 Console.ReadKey();
33 }
34 }
我們來用reflector工具來查看它的IL代碼如下:
.method public hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 3
.locals init (
[0] int32 num,//這裡我建立的明明是i反編譯確是num 不理解,求大家指出
[1] int32 j,//這裡我自己修改成了j
[2] string str,
[3] class TestNewFunction.MyClass myClass,
[4] valuetype TestNewFunction.MyStruct myStruct)
L_0000: nop
//手動初始化i為0
L_0001: ldc.i4.0
L_0002: stloc.0
//通過new來初始化j為0
L_0003: ldc.i4.0 //j的值為0
L_0004: stloc.1
//調用newobj初始化字串str
L_0005: ldc.i4.s 0x23//‘#‘的16進位
L_0007: ldc.i4.s 10//這個10應該是count
L_0009: newobj instance void [mscorlib]System.String::.ctor(char, int32)
L_000e: stloc.2
//調用newobj建立對象,並調用建構函式初始化 ,記憶體配置在託管堆上
L_000f: ldc.i4.s 0x7b//111的十六進位
L_0011: newobj instance void TestNewFunction.MyClass::.ctor(int32)
L_0016: stloc.3
//載入結構體
L_0017: ldloca.s struct2
L_0019: ldstr "hehe"
//調用建構函式初始化,記憶體配置線上程的棧上面
L_001e: call instance void TestNewFunction.MyStruct::.ctor(string)
L_0023: nop
L_0024: ldloc.1
L_0025: call void [mscorlib]System.Console::WriteLine(int32)
L_002a: nop
L_002b: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
L_0030: pop
L_0031: ret
}
本人對IL知道的不是很多,有錯誤希望大家能夠提出來。通過以上分析,可以得出一點結論:
- new一個class時,先調用newobj命令 來為執行個體在託管堆中分配記憶體,然後調用建構函式來進行對象初始化。
- new 一個struct 時,直接調用其建構函式完成初始化。
- new 一個int時,用於初始化其值為0。
差點忘了 new運算子不可重載,分配記憶體失敗時,會引發OutOfMemoryException異常。
以上是本人對new這個關鍵字的用法。如有錯誤歡迎指出。
原文出處:章出處:http://www.cnblogs.com/xingbinggong/archive/2011/07/05/2098454.html
.Net 基礎new關鍵字的用法