引用类型与值类型
摘录:
线程堆栈和线程堆:都是内存区域,值类型分配在堆栈上【后进先出】;引用类型变量分配在堆栈上,内容分配在堆上;
1.值类型
a.值类型包括结构和枚举,引用类型包括类、接口、委托等。还有一种特殊的值类型,称为简单类型(Simple Type),比如 byte,int等
b.所有的值类型都隐式地继承自 System.ValueType类型(注意System.ValueType本身是一个抽象类),所以不能显示让一个值类型(结构)再继承另外一个类,因为c#不支持多重继承,而System.ValueType和所有的引用类型都继承自 System.Object基类,
c.当声明一个值类型的变量(Variable)的时候,变量本身包含了值类型的全部字段,该变量会被分配在线程堆栈(Thread Stack)上。
d.编译器隐式地会为结构类型创建了无参数构造函数。在这个构造函数中会对结构成员进行初始化,所有的值类型成员被赋予0或相当于0的值(针对Char类型),所有的引用类型被赋予null值。(因此,Struct类型不可以自行声明无参数的构造函数)。所以,我们可以通过隐式声明的构造函数去创建一个ValPoint类型变量:
public struct ValPoint
{
public int x;
public ValPoint(int x)
{
this.x = x;
}
}
ValPoint vPoint1 = new ValPoint(); Console.WriteLine(vPoint.x); // 输出为0 我们将上面代码第一句的表达式由“=”分隔拆成两部分来看:
•左边 ValPoint vPoint1,在堆栈上创建一个ValPoint类型的变量vPoint,结构的所有成员均未赋值。在进行new ValPoint()之前,将vPoint压到栈上。
•右边new ValPoint(),new 操作符不会分配内存,它仅仅调用ValPoint结构的默认构造函数,根据构造函数去初始化vPoint结构的所有字段。
注意上面这句,new 操作符不会分配内存,仅仅调用ValPoint结构的默认构造函数去初始化vPoint的所有字段。那如果我这样做,又如何解释呢?
Console.WriteLine((new ValPoint()).x); // 正常,输出为0
//在这种情况下,会创建一个临时变量,然后使用结构的默认构造函数对此临时变量进行初始化。
2.引用類型
public class RefPoint
{
public int x;
public RefPoint(int x)
{
this.x = x;
}
public RefPoint() { }
}
当我们仅仅写下一条声明语句:
RefPoint rPoint1; //它的效果是仅仅在堆栈上创建一个不包含任何数据,也不指向任何对象(不包含创建在堆上的对象的地址)的变量。
而当我们使用new操作符时:
rPoint1= new RefPoint(1);
会发生这样的事:
1.在应用程序堆(Heap)上创建一个引用类型(Type)的实例(Instance)或者叫对象(Object),并为它分配内存地址。
2.自动传递该实例的引用给构造函数。(正因为如此,你才可以在构造函数中使用this来访问这个实例。)
3.调用该类型的构造函数。
4.返回该实例的引用(内存地址),赋值给rPoint变量。
/////////////小结值参数、引用类型参数、输出参数///////////////////////////
1.值参数
数据通过复制实参的值传给形参,方法被调用时,系统做如下操作:
A.在栈中为形参分配空间
B.复制实参的值到形参,这样形参中的值的改变不会影响原来实参中的值,只是原来实参值的一份拷贝。
------------实参不一定是变量,它可以是任何能计算成相应数据类型的表达式。
2.引用参数
必须在方法地声明和调用中都使用ref修饰符,实参必须是变量,在用作实参前必须被赋值,如果是引用类型变量,可以赋值为一个引用或null值
A.不在栈中为形参分配新的内存
B.形参的名称相当于实参变量的别名,跟实参一样引用相同的内存位置。
3.输出参数
用于从方法体内把数据传出到调用代码,它们非常类似于引用参数。
A.必须在声明的调用中都使用out修饰符
B.实参必须是变量,不能是其他表达式类型
C.不在栈中为形参分配新的内存
D.形参的名称相当于实参变量的别名,跟实参一样引用相同的内存位置。
E.在方法内部,输出参数在被读取之前必须被赋值。
F.每个输出参数在方法返回之前必须被赋值。
4.参数数组
它允许零个或多个实参对应一个特殊的形参。
A.在一个参数列表中只能有一个参数数组
B.如果有,它必须是列表中的最后一个
eg: void ListInts(params int[] inVals) { }