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


值類型和引用類型:

C#數據類型分為兩大類:值類型和引用類型。

值類型數據主要有:結構體struct,枚舉體enum,布爾型bool,浮點型,整型。

引用類型數據主要有:數組,字符串,接口,委托,類。

值類型和引用類型的區別:

  引用類型繼承自System.Object,值類型繼承自System.ValueType。

  引用類型保存到內存的堆heap中,值類型保存在內存的堆棧stack中。在.net中,棧的內存是自動釋放的,而堆會有垃圾回收器GC來釋放。

  引用類型可以派生出新的類型,而值類型不可以。引用類型可以包含null值,而值類型不可以。

  引用類型變量賦值只復制對象的引用,不復制對象本身。而將一個值類型變量賦給另一個值類型變量時,將復制包含的值。

下面一個小例子可以簡單說明值類型和引用類型:

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都是按值傳遞的,可以這么理解,這個值傳遞其實是實參地址的拷貝,得到這個拷貝地址后,你可以通過它修改這個地址的內容,因為此時這個內容的地址和原地址是同一個地址,但是你不能修改這個地址本身使其重新引用其它的對象,所以也可以說成是指傳遞。但同時因為形參的引用地址和實參的引用地址是相同的,因此對形參的修改也會影響實參變量。

 

說明:不管是對象、基本類型還是對象數組、基本類型數組,在函數中都不能改變其實際地址但能改變其中的內容。

這里加入一張網上拷貝的圖片便於理解:

 

 

關於值傳遞和引用傳遞,網上還有這么一種說法:其實都是對“=”的理解

1、= 是賦值操作(任何包含=的如+=、-=、 /=等等,都內含了賦值操作)。不再是你以前理解的數學含義了,而+ - * /和 = 在java中更不是一個級別,換句話說, = 是一個動作,一個可以改變內存狀態的操作,一個可以改變變量的符號,而+ - * /卻不會。這里的賦值操作其實是包含了兩個意思:1、放棄了原有的值或引用;2得到了 = 右側變量的值或引用。Java中對 = 的理解很重要啊!!可惜好多人忽略了,或者理解了卻沒深思過。

2、對於基本數據類型變量,= 操作是完整地復制了變量的值。換句話說,“=之后,你我已無關聯”;至於基本數據類型,就不在這科普了。基本類型:Byte\Short\int\long\float\double\char\boolean.

3、對於非基本數據類型變量,= 操作是復制了變量的引用。換句話說,“嘿,= 左側的變量,你丫別給我瞎動!咱倆現在是一根繩上的螞蚱,除非你再被 = 一次放棄現有的引用!!上面說了 = 是一個動作,所以我把 = 當作動詞用啦!”。而非基本數據類型變量你基本上可以

4、參數本身是變量,參數傳遞本質就是一種 = 操作。參數是變量,所有我們對變量的操作、變量能有的行為,參數都有。所以把C語言里參數是傳值啊、傳指針啊的那套理論全忘掉,參數傳遞就是 = 操作。

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM