C#类型基础----引用类型

C#类型基础----引用类型

 

前言

上一讲说了一下值类型的部分内容,虽然没有什么有意思的东西能吸引大家的注意,也没啥好的代码让大家参考一下,但是楼主的水平实在有限,各位看官如果不嫌弃的话,还是看看吧,如果对你的生活或者学习有那么一丝帮助的话,都算是楼主的万幸.

 

正文

当声明一个引用类型变量,并使用new操作符创建引用类型实力的时候,该引用类型的变量会被分配到线程栈上,变量保存了位于堆上的引用类型的实例的内存地址.变量本身不包含任何类型所定义的数据.如果仅仅声明一个变量,但不使用new操作符,由于在堆上还没有创建类型的实例,因此,变量值为null,意思是不指向任何对象(堆上的对象的实例).对于变量的类型声明,用于限制此变量可以保存的类型实例的地址.

 

说明:这里有一些概念可能容易混淆,那就是变量(Variable),对象(object),实例(Instance).变量可以是一个值类型,也可以是一个引用类型.当变量是引用类型时,由于本身只包含实际对象的引用(内存地址),因此也叫做对象引用.而在对象创建的对象,称为对象的实例(根据类的定义分配了内存).从一段简单的代码也可以看出,如果运行object a=null;Console.WriteLine(a.ToString());,会得到运行时错误”未将对象引用设置到对象的实例”.因此变量a是一个对象引用,因为没有使用new操作符,所以它没有指向任何的对象实例.

 

如果有一个这样的类,它依然代表直线上的一点:

    public class RefPoint
    {
        public int x;
        public RefPoint(int x) { this.x = x; }
        public RefPoint() { }
}

当仅仅写下一条声明语句时:

它的效果如下图所示,在线程栈上创建一个不包含任何数据,也不知想任何对象的(不包含内存地址)的变量:

 

 

当使用new操作符时:

rPoint1= new RefPoint(1);

则会完成下面几件事情:

1.在应用程序堆上创建一个引用类型对象的实例,并为它分配内存空间.

2.自动传递该实例的运用给构造函数.(正因为如此,才可以在构造函数中使用this来访问这个实例.)

3.调用该类型的构造函数.

4.返回该实例的引用(内存地址),赋值给rPoint1变量,如下图所示:

 

 

简单类型

 

很多时候大家喜欢用int类型作为值类型的实例,object类型作为引用类型的实例来说明问题.但是今天咱们采用自定义的结构和类,分别对值类型和引用类型进行说明.这是因为简单类型(比如int)有一些框架类库已经实现了的行为,这些行为会让我们对一些操作产生误解.或者说,用他们作为示例还不够纯粹.

举个例子,如果我们想比较两个int类型是否相等,通常会这样:

int i=3;
int j=3;
if(i==j)
Console.WriteLine(“ i equals to j ”);

但是,对于自定义的值类型,比如结构,就不能用”==”来判断它们是否相等,而需要在变量上调用Equals()方法来完成.

再来个例子,大家知道string是一个引用类型,在比较他们是否相等的时候,通常会这样做:

string a=”123456”;
string b=”123456”;
if(a==b)
Console.WriteLine(“a equals to b”)

貌似也能说明引用类型比较相等的时候可以使用”==”,实际上,在后面就能够看到,当使用”==”对引用类型变量进行比较的时候,比较的他们是否指向堆上同一个对象.而上面a,b指向的显然是不同的对象,只是对象包含的值相同,所以可见,对于string类型,对他们的比较实际上比较的是值,而不是引用(string是一种特殊的的引用类型,它的特殊性在于它是不可变类型,以后会说).

为了避免上面这些引起的混淆,在对象判等部分将采用自定义的结构和类来分别说明.

 

拆装箱

 

简单来说,装箱就是讲一个值类型转换成等价的引用类型.它的过程分为这样几步:

(1)在堆上为新生成的对象实例分配内存.该对象实例包含数据,但它没有名称.

(2)将栈上值类型变量的值赋值到堆上的对象中.

(3)将对象创建的对象的地址返回给引用类型变量.

因此,当我们运行这样的代码时:

int i=1;
object boxed=i;
Console.WriteLine(“Boxed Point : ”+boxed);

效果如下图所示:

 

(装箱)

 

而拆箱则是将一个已装箱的引用类型转换为值类型:

int i=1;
object boxed=i;
int j;
j=(int)boxed;
Console.WriteLine(“UnBoxed Point : ”+j);

需要注意的是拆箱操作分为两步来完成:

(1)获取已装箱的对象的地址.

(2)将值从堆上的对象中复制到堆栈上的值变量中.

 

可见,拆装箱需要反复在对上进行操作,因此,在程序中应该尽量避免无意义的拆装箱.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值