值類型和引用類型及參數傳遞

值類型和引用類型: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語言裏參數是傳值啊、傳指針啊的那套理論全忘掉,參數傳遞就是 = 操做。

相關文章
相關標籤/搜索