Stay hungry,Stay foolish!

0%

C#值类型和引用类型

C#有值类型和引用类型,简单来说,值类型就是存储其值的,引用类型是存储对值的引用,也就是存储的是地址。值类型存储在堆栈中,引用类型存储在托管堆上。

1 值类型

C#内置的基本数据类型都是值类型,如下:byte,short,int,long,float,double,decimal,char,bool 和 struct 。

值类型变量声明后,不管是否已经赋值,编译器为其分配内存。

如果声明一个值类型变量,并把它赋予给另外一个值类型变量,那么在内存中就有两个值了。

1
bool p, q;
2
p = true;
3
q = p;
4
q = false;

第一行声明的时候,会初始化一个false给p,q;

第二行将p的值赋为true;

第三行的q = p;即将p的值赋给q,此时内存又两个bool对象。到了第四行q = false时,只改变q这个对象的值。不会改变p的值,因为他们两个所指向的内存地址是不一样的。

而引用类型就跟值类型不一样。

2 引用类型

C#支持两种预定义的引用类型:object,string。
大多数更复杂的数据类型,包括我们自己声明的类,都是引用类型。

1
Student s1,s2;   // 声明两个类型变量
2
s1 = new Student();    // 实例化
3
s1.stuName = "zhang";
4
s2 = s1;   
5
s2.stuName = "huang";

执行完这段代码之后,只有一个Student对象。s1,s2都指向这个对象。

一开始将s1实例化,然后将其属性stuName赋值为“zhang”。之后s2 = s1,因为s2没有用new关键字创建对象,此时s2,s1都指向原来那个对象。之后s2.stuName = “huang”; 因为都是指向内存的同一个位置,因此会把原来的”zhang”覆盖掉。

虽然string也是引用类型,但是string类型不会出现上述的情况。比如:

1
string str1, str2;
2
str1 = "hello";
3
str2 = str1;
4
str2 = "world";

运行完这段代码,str1的值为”hello”,而不是和预想的”world”那样。

解释:
当用”hello”初始化str1时,就在堆上分配了一个新的string对象,str2 = str1时,str2也是指向这个string对象的,所以其值也是”hello”。当执行 str2 = “world”; 时,在堆上为新值”world”重新分配了一个对象,因此不会改变原来的str1的值,这是运算符重载的结果。