值类型和引用类型

来源:互联网 发布:滚雪球官网数据档案 编辑:程序博客网 时间:2024/06/08 19:17
 变量、常量和杖举
  常量:用来代替一个数或字符串的名称,我们可以在初始化时定义。在变量前增加关键字“const”,就可以把这个变量设置为常量。
  语法如下:
     访问修饰符 const 数据类型 常量名 = 值
 注:常量在使用过程中是不能被修改的,如果要修改一个常量的话程序会发生错误。
  杖举:事先考虑到某一变量可能取得值,尽量用自然语言中含义清楚的单词来表示它的每一个值。用杖举得方法定义的类型称为杖举类型。杖举是一个被命名的整型常数的集合。定义一个杖举得关键字是“enum”,语法如下:
   public enum 杖举名
 {
   标识符[=整型常数],
   标识符[=整型常数],
   .....
 }
注:如果杖举没有初始化,即省掉“=整型常数”时,则从第一个标识符开始,顺次赋给标识符0,1,2,...。但当杖举中得某个成员赋值后,其后的成员按依次加1的规则确定其值。例如:
   public enum Sex
  {
    男=1,
    女
  }
 杖举的第一个元素“男”显式的赋值是“1”,那第二个元素“女”对应的数值就自动的变成2了。
还可以对杖举进行类型转换,可以用int类型来表示一个杖举,如下:
  Reader reader = new Reader();
  reader.getWeek=((weekDay)2);
还可以反过来,由杖举转换为数字,如下:
  int k = (int) weekDay.女;
再有,我们也可以用字符串来代替杖举,如下:
  string[] BookType = {"文学","物理","数学","计算机","外语"};
  Console.WriteLine("我喜欢的类型是{0}",BookType[2]);
使用杖举得优势如下:
  ◇ 杖举是强类型的,可以避免类型错误,在输入了与声明不一致的杖举值的时候,会产生编译错误。
  ◇ 杖举使代码更清晰,允许用描述性的名称表示整数值,而不是用含义模糊的数来表示,增加了程序的可读性和可维护性。
  ◇ 杖举使代码更易于键入。在给杖举类型的实力赋值时,VS.NET IDE 会通过智能提示符(“.”)弹出一个包含可接受的列表框,减少了按键次数,并能让我们回忆起可能的值。
 类和结构
 结构:将一个对象作为内置的一个数据类型以加快分配。定义结构的关键字是struct,语法如下:
        访问修饰符 struct 结构名   
        {
              ////结构体
        }
 注:结构的定义和类很相似,可以有字段,可以有方法。但是当在结构中定义字段的时候,字段不能赋值。
结构的使用:在不使用结构的属性时可以不用new,直接使用,但是在定义结构的时候,必须为结构的成员赋初值,然后直接用名字就可以了。如下:
   ReaderStruct reads;
   reads._sge = 13;
   reads._name = "张三";
 但是如果使用结构中的属性等成员,必须要先把结构用new实例化才能使用。如下:
   ReaderStruct reads = new ReaderStruct();
   reads.Age=13;
   reads.Name="张三";
在实例化类的时候,其实是调用类的构造方法。结构和类相似,也有它自己的构造方法。C#给结构提供了一个无参构造方法,但是和类不一样的是结构中不能包含显式的无参构造方法,那是因为CLR并不要求结构必须定义构造方法。实际上C#编译器也不会为结构产生默认的无参构造方法。但CLR允许我们为结构定义构造方法。当我们使用构造方法时,只有显式调用时构造方法才会被执行。用new来创建一个结构时,只是调用的他得构造方法。如果不适用new来创建,那么结构的字段都会保持为0,因为在调用构造方法之前系统为该对象分配的内存总是被设置为0。由于结构是引用类型,所以结构的值总不能为null。
 注意:不能给结构显式定义一个无参构造方法。我们在使用结构的构造方法时,必须是有参的构造方法,而且在构造方法中,必须把结构中所有的字段赋值。
结构和类的区别:
             结构                                           类
    值类型,在堆栈上分配地址                       引用类型,在堆上分配地址
    没有 默认的构造方法,但是可以添加构造方法       有默认的构造方法
    没有析构函数                                  有析构函数
    不能给字段赋值                                可以给字段赋值
    不能有 protected 修饰符                       可以使用
    不能添加无参构造方法                           可以添加
    不能被继承                                    能被继承
注意:结构的存储位置是在堆载上而类的存储位置是在堆上,堆载的空间有限,所以表示如点,矩形和颜色这样的轻量对象的时候,我们可以选择结构来实现,结构是值类型,开销小,效率高,主要用于组织数据。对于大量的逻辑的对象,创建类要比创建结构要好。
值类型和引用类型
 值类型:C#的值类型派生于System.ValueTye基类。当创建一个值类型的时候,都会在堆栈上开辟一块新的内存空间来保存值,当修改这个值的时候其实是修改它所在的内存空间的值。这就相当于创建了一个对象的副本,也就是复制了某个对象。一般来说值类型包含基本的数据类型,结构,杖举等。
 引用类型:C#的引用类型派生于System.Object基类。当创建一个引用类型的时候,在堆栈上分配一快空间,用来存储引用类型(类)对象,当给这个引用类型赋值的时候,在堆栈上划分一块空间用来存储类在这个堆上的地址(当给这个地址起名字的时候就是所定义的变量名)。其实我们可以这样认为,在给引用类型(如类)赋值的时候,其实赋值的是引用类型的地址。当类作为参数的时候,当参数被修改的时候,会修改类成员的值。因为他们指向同一地址内容。
 其实值类型和引用类型的最主要的区别就是存储方式的不同。
装箱和拆箱
 装箱:由值类型转换为引用类型。
 拆箱:由引用类型转换为值类型。
例如:将一个整型(int)赋值给一个Object类型的变量:
          int i = 123;
          object o = i;
 注:第2句代码讲值类型的数据“123”放到了一个Object类型的变量o中,而o是一个引用类型变量,其引用的对象保存在堆中。CLR讲值类型的数据“包裹”到一个匿名的对象中,并将此对象中引用放在Object类型的变量o中,这个过程称为“装箱”。
  拆箱的过程如下:
          int i =123;
          object o = i;
          int j =(int)o
注意:装箱操作可以隐式进行但拆箱操作必须是显示的。拆箱过程分为两步:1,检查这个对象实例,看它是否为给定的值类型的装箱值。2,把这个实例的值拷贝给值类型的变量。  在拆箱的时候要注意类型的转换,所定义的值类型要与引用类型的数据类型一致,否则会发生类型转换的异常。