值類型和引用類型:java
C#數據類型分爲兩大類:值類型和引用類型。數組
值類型數據主要有:結構體struct,枚舉體enum,布爾型bool,浮點型,整型。函數
引用類型數據主要有:數組,字符串,接口,委託,類。spa
值類型和引用類型的區別:.net
引用類型繼承自System.Object,值類型繼承自System.ValueType。指針
引用類型保存到內存的堆heap中,值類型保存在內存的堆棧stack中。在.net中,棧的內存是自動釋放的,而堆會有垃圾回收器GC來釋放。code
引用類型能夠派生出新的類型,而值類型不能夠。引用類型能夠包含null值,而值類型不能夠。對象
引用類型變量賦值只複製對象的引用,不復制對象自己。而將一個值類型變量賦給另外一個值類型變量時,將複製包含的值。blog
下面一個小例子能夠簡單說明值類型和引用類型:繼承
class PointR { public int x, y; } struct PointV { public int a, b; } class Program { static void Main(string[] args) { //給一個引用類型賦值將複製到一個對象的引用,而給一個值類型賦值將複製一個對象的值 PointR r; PointV v; r = new PointR(); v = new PointV(); r.x = 7; v.a = 7; PointR pr = r; PointV pv = v; pr.x = 9; pv.a = 9; Console.WriteLine(r.x);//9 Console.WriteLine(v.a);//7 Console.Read(); } }
C#參數傳遞:
.net默認的是經過值傳送變量,可是也能夠迫使值參數經過引用傳送給方法。C#要求對傳遞給方法的參數進行初始化。在傳遞給方法以前,不管時按值傳遞,仍是按引用傳遞,變量都必須初始化。 ref關鍵字:能夠迫使值參數經過引用傳送給方法。即:在.net中,若是把一個參數傳遞給方法,且這個方法的輸入參數前帶有ref關鍵字,則該方法對變量所作的任何改變都會影響原來對象的值。下面一個小例子說明按值傳遞和ref參數傳遞:
class Program { //默認值,C#的參數是按值傳遞的,這也是最多見的狀況 static void Method1(int p) { ++p; } //爲了按引用傳遞,C#提供了參數修飾字ref,。ref修飾字要求變量在傳遞給方法以前必須賦值 static void Method2(ref int p) { ++p; } static void Main(string[] args) { int x = 9; int y = 9; Method1(x); Method2(ref y); Console.WriteLine(x);//9 Console.WriteLine(y);//10 Console.Read(); } }
在方法的輸入參數前面加上out關鍵字時,傳遞給該方法的變量能夠不初始化。該變量經過引用傳遞,因此在從被調用的方法中返回時,方法對該變量進行的任何改變都會保留下來。在調用該方法時,還須要使用out關鍵字,這與在定義該方法時同樣。而且out修飾字要求變量在從方法返回時必須賦值。舉例說明:
class Program { //out修飾字要求變量在從方法返回時必須賦值 static void Split(string name, out string firstName, out string lastName) { int i = name.LastIndexOf(' '); firstName = name.Substring(0, i); lastName = name.Substring(i + 1); } static void Main(string[] args) { string a, b; Split("zhou enlai", out a, out b); Console.WriteLine("{0}+ {1}", a, b);//zhou+ erlai Console.Read(); } }
還有一個params修飾傳遞參數,很少說,直接舉例:
class Program { //params 修飾字可使用在方法的最後一個參數上,這樣方法就能夠接受任意數目的某種類型的參數 static int Add(params int[] arr) { int sum = 0; foreach (int i in arr) { sum += i; } return sum; } static void Main(string[] args) { int i = Add(1, 1, 2, 3, 4, 5, 6); Console.WriteLine(i);//22 Console.Read(); } }
補充:
原由是網上看到一句話:java裏面的參數傳遞都是按值傳遞的。不理解,因而查詢資料:
java數據類型分類兩大類:基本類型和對象類型,相應的,變量也分爲基本類型和引用類型。
基本類型數據有:byte\short\int\long\float\double\char\boolean
整數類型:byte是8位字節,範圍是-128-127,short是16位的,int是32位,long是64位
浮點數:float是32位,1位符號位,7位指數,23位有效尾數;double是64位,1位符號位,11位指數,52位有效尾數;
字符:char是16位字節
布爾類型:boolean。
基本類型的變量保存自己的數值,「引用值」則保存內存空間地址,表明了對某個對象的引用,而不是對象自己。
基本類型的變量在聲明時則由系統自動分配內存空間,不能包含null;而引用類型的變量在聲明時僅僅是對變量分配了引用空間,而不分配數據空間,能夠賦予null值。
值傳遞:
值傳遞在進行方法調用時,實際參數把它的值傳遞給對應的形參,函數接收的形參數組實際上是實參數值的拷貝,對形參進行修改不會影響實際參數的數值。
引用傳遞:
引用傳遞在進行方法調用時,實際參數把它對對象的引用傳遞給形參變量,而不是將對象傳遞給形參變量,在進行方法調用過程當中,實參變量和形參變量具備相同的數值,都是指向同一塊內存地址,對形參數值進行改變,改變的是內存地址中的實際對象,形參變量自己的引用數值不會獲得改變。
此處須要考慮String、Integer、Double等基本基本類型包裝類,它們都是immutable類型,由於它們都沒有自身修改操做的函數,因此對它們的每次操做都是從新建立一個對象,所以能夠將它們看成基本類型使用,在參數傳遞時能夠按照值傳遞來考慮。
綜合,上文說的java都是按值傳遞的,能夠這麼理解,這個值傳遞實際上是實參地址的拷貝,獲得這個拷貝地址後,你能夠經過它修改這個地址的內容,由於此時這個內容的地址和原地址是同一個地址,可是你不能修改這個地址自己使其從新引用其它的對象,因此也能夠說成是指傳遞。但同時由於形參的引用地址和實參的引用地址是相同的,所以對形參的修改也會影響實參變量。
說明:不論是對象、基本類型仍是對象數組、基本類型數組,在函數中都不能改變其實際地址但能改變其中的內容。
這裏加入一張網上拷貝的圖片便於理解:
關於值傳遞和引用傳遞,網上還有這麼一種說法:其實都是對「=」的理解
一、= 是賦值操做(任何包含=的如+=、-=、 /=等等,都內含了賦值操做)。再也不是你之前理解的數學含義了,而+ - * /和 = 在java中更不是一個級別,換句話說, = 是一個動做,一個能夠改變內存狀態的操做,一個能夠改變變量的符號,而+ - * /卻不會。這裏的賦值操做實際上是包含了兩個意思:一、放棄了原有的值或引用;2獲得了 = 右側變量的值或引用。Java中對 = 的理解很重要啊!!惋惜好多人忽略了,或者理解了卻沒深思過。
二、對於基本數據類型變量,= 操做是完整地複製了變量的值。換句話說,「=以後,你我已無關聯」;至於基本數據類型,就不在這科普了。基本類型:Byte\Short\int\long\float\double\char\boolean.
三、對於非基本數據類型變量,= 操做是複製了變量的引用。換句話說,「嘿,= 左側的變量,你丫別給我瞎動!咱倆如今是一根繩上的螞蚱,除非你再被 = 一次放棄現有的引用!!上面說了 = 是一個動做,因此我把 = 看成動詞用啦!」。而非基本數據類型變量你基本上能夠
四、參數自己是變量,參數傳遞本質就是一種 = 操做。參數是變量,全部咱們對變量的操做、變量能有的行爲,參數都有。因此把C語言裏參數是傳值啊、傳指針啊的那套理論全忘掉,參數傳遞就是 = 操做。