1. 程式人生 > >值型別和引用型別,形參和實參,傳值和傳引用

值型別和引用型別,形參和實參,傳值和傳引用

    C# 中有兩種型別:引用型別和值型別。引用型別的變數儲存對其資料(物件)的引用地址),而型別的變數直接包含其資料(副本)。     對於引用型別,兩種變數可引用同一物件;因此,對一個變數執行的操作會影響另一個變數所引用的物件。對於值型別,每個變數都具有其自己的資料副本,對一個變數執行的操作不會影響另一個變數(ref 和 out 引數變數除外)。     形參:函式定義時所帶的引數如:void add(int i,double t)中的 i 和 t      實參:將要傳人函式內進行運算的引數,可以是變數、常量,與形參型別相同;如:add( 1 , 2 )中 1 和 2 就是實參——實際引數  
傳值:

只會在呼叫函式的這個作用域中起作用。 

傳值呼叫的情況是這樣的:實參把值傳入堆疊然後發生傳遞過程,形參接受這個值,也可以改變這個值,形參可以在自身的函式中有很多變數,可以進行運算,改變他們的值,但問題的關鍵是,這些變數開闢的記憶體空間都是在堆疊中的,在呼叫結束的一瞬間堆疊全都釋放彈棧了,所有的堆疊的記憶體空間都沒了,存放的資料也就跟著消失了。這個就是傳值不影響實參的根本原因。

    在函式呼叫中發生的資料傳送是單向的。 即只能把實參的值傳送給形參,而不能把形參的值反向地傳送給實參。 因此在函式呼叫過程中,形參的值發生改變,而實參中的值不會變化。

傳引用:

   真正的以

地址的方式傳遞引數

   傳遞以後,行參和實參都是同一個物件,只是他們名字不同而已對行參的修改將影響實參的值。

   它其實和傳值基本一樣的傳送過程,但是關鍵就在於在剛開闢堆疊的時候,它放入的是由主調函式放進來的實參變數的地址,被調函式對形參的任何操作都被處理成間接定址,即通過堆疊中存放的地址訪問主調函式中的實參變數,那麼形參在修改的時候,修改的就是實參地址所對應的值,也就是實參的值,雖然隨著堆疊的消失,這個實參地址和形參都消失了,但修改的內容卻不在堆疊所開闢的記憶體中,它一直存在著,而且這個記憶體就是原來用來存放實參的。

何時傳值、何時傳引用:

如果傳遞的引數是基元型別(int,float等)或結構體
(struct),那麼就是傳值呼叫。
如果傳遞的引數前有ref或者out關鍵字,那麼就是傳引用呼叫。
如果傳遞的引數是類(class)並且沒有ref或out關鍵字:
     如果呼叫的函式中對引數重新進行了地址分配(new操作),那麼執行結果類似傳值呼叫
     如呼叫的函式中沒有對引數重新進行了地址分配,直接就是使用了傳遞的引數,執行結果類似傳引用呼叫

 舉個例子:

String是final型別,比如String s="123"; s = "abc",後面的“abc”其實是新建了一個string物件,並重新將其地址給了s。所以函式內的string物件是副本,副本重新指向另外一個地址,對本來的string物件無影響。
     而StringBuffer非final型別,StringBuffer s=“123”;s=“ABC”其傳入函式的是他的物件地址的副本,還是指向同一物件。在函式內對其副本操作,等同於對原來StringBuffer物件的操作。

thanks for your time