前言 這幾天一直在思考這章討論什麼, 在上一章討論string的時候牽涉到引用類型,那麼我們這一章討論討論一下,值類型和引用類型。 值類型和引用類型,它們的區別來源於傳值方式。有人會認為值類型就存在棧上這是不一定的。詳細看下文。 有些人會說啊。。有垃圾回收機制進行清理內存。。不需要去折騰那麼多吧 - -!。。。。。為了寫好代碼,避免面試問到。。還是勉為其難的討論討論吧。。。。。 值類型和棧 棧,存儲不是對象成員的值數據類型,還存放著局部變量,參數。 那麼他的工作原理是怎樣的呢?首先要知道,數據在棧上,是從高內存位置往低內存位置填充的,變量地址不會重復的。 假如有下面一段代碼: 從上面可以看見,b代碼塊是嵌套a代碼塊裡。由於代碼從上到下的執行順序,那麼變量a會比變量b先入棧;可是b代碼塊會比a代碼早結束,超出作用域之後,變量就會釋放,因此,變量b會比變量a先釋放。 由此可見,靈活性並不高,如果希望生命活得長久點?這個時候,堆的作用就體現出來。 引用類型和堆 堆,它的特性和棧有點相反,存儲的是對象成員類型,是從低內存位置往高內存位置填充的。當值類型的變量為類型成員的時候,是與對象存放在堆裡。 先說下工作原理,有這樣一段代碼。 復制代碼 class Program { static void Main(string[] args) { Human h; h = new Human(); } } 復制代碼 首先,會在棧上分配一個空間,存放引用h,它僅僅是一個引用,不是對象。到第二句進行實例化對象,new 運算符是用來請求分配儲存空間的,CLR會搜索堆上足夠的位置,分配給對象,然後new會返回它所在堆上的地址給引用。因此在棧上存放著該引用指向堆上的對象的地址。 綜上所述: 值類型的使用減少了堆的壓力,同時減少垃圾回收的次數。引用類型卻彌補了生命周期的不足,增加了靈活性。 值類型創建變量時是賦予默認值的,例如int默認值是0。而引用類型創建變量,默認是null。那麼,沒有對象的引用類型的變量使用時會報異常NullReferenceException。 值類型的變量是以復制的方式賦值,執行一次逐字段的復制,而引用類型將對象在堆上的地址賦於新變量進行引用。 下面有段代碼充分說明了引用類型和值類型的區別 :(借用Clr C#的例子) 復制代碼 struct Struct//值類型 { public int x; } class Class //引用類型 { public int x; } class Program { static void Main(string[] args) { //代碼A Struct s1 = new Struct(); //分配在棧上 Class c1 = new Class(); //分配在堆上 s1.x = 1; c1.x = 1; Console.WriteLine(s1.x); //輸出1 Console.WriteLine(c1.x); //輸出1 //代碼B Struct s2 = s1; //復制棧上成員給s2 Class c2 = c1; //復制引用給c2 s2.x = 2; //值類型,s1.x不變,s2.x 變更 c2.x = 2; //引用類型,c1.x和c2.x 同時改變 Console.WriteLine(s1.x); //1 值類型 Console.WriteLine(s2.x); //2 值類型 Console.WriteLine(c1.x); //2 引用類型 Console.WriteLine(c2.x); //2 引用類型 } } 復制代碼 c1將地址復制給c2,也就是說c1和c2指向的是同一個對象,因此c1和c2其中一個修改了,另外的也會受影響。 s1將成員復制給s2,雖然s1和s2存儲了相同的值,但是他們內存地址都不相同,存的是屬於自己的值,因此s1和s2其實一個修改了,也不會影響另外一個。 結尾 寫到這裡也差不多了。其實說到引用類型和值類型,還說牽涉到裝箱和拆箱的,小弟對那塊還沒多深的了解,等以後再和大家探討。 感冒了。。休息去。。。一個多星期還沒好,今天貌似又嚴重了。。公司的流感太厲害了。。希望各位注意身體。。=。=。。。。。