《.NET4.0 面向对象编程漫谈》读书笔记 ——第2章 数据类型趣谈

时间:2021-05-12 22:10:25

【简述:】
      本章主要谈了值类型与引用类型。其中值类型讲述了BigInteger、Nullable<T>,引用类型讲述了String。通过Object类型值类型与引用类型建立关联。最后谈了用途极广的泛型。

 第一节 数值类型的使用

 1、  数值类型的自动转换与强制转换
当数值类型由“由大到小”转换时----如double类型转为float类型时,这时需要强制转换,可能造成数据丢失,因此代码被视为缺陷代码,你只需要依据数值的大小选择合适的数据类型即可。
【案例】
Int32 i = 0;

float f = float.MaxValue;  // float 类型的最大值

i = (Int32)f;

Console.WriteLine(i);

程序输出结果:-2147483648

 2、  基于天文数字的计算

    为了方便“天文数字”的计算,.net4.0类库引入大整数类型--- BitInteger

   【书中案例注释】

    A、BigInteger类型定义于System.Numerics

    B、Fibonacci数列:指斐波那契数列,1、1、2、3、5、8、13、21、……

    C、当定义为long,计算第93个斐波那契数时,即引发OverflowException(算术运算溢出异常)。

   而定义为BigInteger时,不会出现。

    D、基于BigInteger,可设计一个带小数点的天文数字的类。

第二节 用好引用类型的变量

 1、  线程堆栈和托管堆

        A、  进程:是系统进行资源分配和调度的一个独立单位。

       B、  线程:是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。每个独立的线 程有一个程序运行的入口、顺序执行序列和程序的出口。多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。

       C、  线程堆栈:每个线程拥有一块自留地,称为线程堆栈。值类型变量所占用的内存线程堆栈中分配的。

       D、  托管堆:另一块内存区域称为堆,在.net托管环境中,堆由CLR管理,因此称为托管堆。

           引用类型变量引用的对象所占用的内存是在托管堆中分配的。

 2、  引用类型变量的内存模型

      A、  引用类型变量生存于线程堆栈中,而它引用的对象生存于托管堆中。引用类型有四种:类类型、接口类型、数组类型、委托类型。

     B、【书中案例注释】
          Objs = new MyClass[10]   指创建了10个引用类型变量,而每个变量其值为null。它并没有创建10个MyClass对象。而要创建需要obj[i] = new MyClass() { Value = i};
         注意:这个对象数组引用(即10个引用变量,是在线程堆栈中创建的,而不是在托管堆中创建的。

 3、“=”和“==”辨析

      A、“=”是赋值运算符,“==”是关系运算符。

      B、两个引用类型变量的相互赋值意味着赋值后两个引量所占用的内存单元其内容是相同的。

      C、定义引用类型变量而又未引用任何对象时,必须给它赋一个null值,否则编译不能通用。

      D、当对于值类型施加于“==”时,是比较两个变量其值是否相等,当对于引用变量时,是比对两个引用变量是否引用 同一对象。

       E、字符串类“==”比较的是对象其值,它违反了规则了吗?没有,因为它对“==”重载了。

第三节    值类型变量的故事

 1、  结构与类相似,也可以拥有方法和构造函数,且CLR不用自动调用结构的构造函数,必须用NEW显式调用。

MyPointF my = new MyPointF(100,200);

Console.WriteLine(my.ToString());

2、  何时选用struct呢?

当要封装的信息量很少,且这些信息均可由值类型字段表达时,用Struct。

3、  因为值类型继承于object,借助装箱与拆箱操作可以把值类型变量看成是引用类型的变量,但会影响程序性能,因此应该尽量避免在程序中使用它。

4、  为什么装箱操作会对性能造成较大影响?
答:首选在托管堆中分配内存,接着创建匿名对象,然后数据复制。

第四节    说不尽的字符串

 1、  String 不是值类型,而是引用类型,它是独特的引用类型。从对象浏览器可证实这一点。

2、  String 可像值类型变量赋值。 String s1 = “abcd”

3、  String 变量的内容是可读的,每赋值一次,重新创建一个字符串,而不是在原有的内存区域扩充而来。 String s1 = “a”; string s1 = “abcd”

4、  string 的“+”运算符,实际上调用Concat方法实现。

5、  引入驻留池,它包含程序中以编程方式声明的字符串常量或显示添加到池中的对象引用。想必引入它是为了提高字符串操作性能而用。

6、  string 使用建议:避免使用加法运算符连接不同类型的数据,在循环中使用StringBuilder代替String实现字符串连接。感叹StringBuilder真是性能太好了,尤其是当循环次数很大时。

 第五节  可取空值的“值类型”

 1、  System.Nullable<T> 被称为可空类型,T? 是其缩写,它为一个值类型。

2、  有可空类型参与的计算,其结果也为可空类型。

3、  当可空类型赋值给值类型时,可这样做:
Int? op1 = null;
Int result = (op1 ?? 0) * 2; //等价于 op1.GetValueOrDefault(0) * 2;

4、主要用途:从DataTable或DataReader赋值给值类型的变量时,用它会很方便。

 第六节  数据类型的模板化----泛型

1、泛型定义中的where 子句所限定的条件称为“泛型类型参数约束”。

2、作者在扩充阅读中所列的dynamic的程序有错误,因为当自定义一个类型若未实现">"运算符重载,程序异常!
3、手工设计的复数类中,有泛型类、泛型方法、泛型结构、泛型接口。

4、泛型的优点:
    A、减少类的数目
    B、剖离数据结构与算法
    C、提升程序运行效率 感到泛型List<int>比ArrayList,运行效率有数倍的提升。
    D、减少编码错误