代码改变世界

4.1 所有类型都从System.Object派生

2011-12-07 10:27  iRead  阅读(318)  评论(0编辑  收藏  举报

  “运行时”要求每个类型最终都从System.Object类型派生。换言之,以下两个类型定义是完全一致的:

  由于所有类型最终都从System.Object派生,所以可以保证每个类型的每个对象都有一组最基本的方法。具体地说,System.Object类提供了如表4.1所示的公共实例方法。

  表4-1 System.Object的公共方法

公共方法

说明

Equals

如果两个对象具有相同的值,就返回true。欲知该方法的详情,请参见5.3.2节“对象相等性和同一性”

GetHashCode

返回对象的值的一个哈希码。如果某个类型的对象要在一个哈希表中作为key使用,该类型应使用这个方法。方法应该为不同的对象提供一个良好的分布。将这个方法设计到Object中并不恰当。大多数类型都永远不会在哈希表中作为键值使用,所以这个方法本来是应该在一个接口中定义的。欲知这个方法的详情,请参见5.4节“对象哈希码”

ToString

该方法默认返回类型的完整名称(this.GetType().FullName)。然而,我们经常需要重写这个方法,使它返回一个String对象,其中包含对象类型的一个表示。例如,核心类型(比如Boolean和Int32)重写了这个方法,返回它们的值的一个字符串表示。另外,我们也经常出于调试的目的而重写该方法(调用后将获得一个字符串,显示了对象的各个字段的值)。事实上,Microsoft Visual Studio的调试器会自动调用该函数来显示对象的一个字符串表示。注意,ToString理论上应该识别与调用线程关联的CultureInfo,并相应地采取操作。第14章将更详细地讨论ToString

GetType

返回从Type派生的一个对象的实例,指出调用GetType的那个对象是什么类型。返回的Type对象可以和反射类配合使用,从而获取与对象的类型有关的元数据信息。反射主题将在第23章“程序集加载和反射”中讨论。GetType方法是非虚方法,这样可以防止一个类重写该方法,并隐瞒其类型,从而破坏类型安全性。

  此外,从System.Object派生的类型能访问如表4-2所示的受保护的方法。

  表4-2 System.Object的受保护方法        

受保护方法

说明

MemberwiseClone

这个非虚方法能创建类型的一个新实例,并将新对象的实例设与this对象的实例字段完全一致。返回的是对新实例的一个引用

Finalize

在垃圾回收器判断对象应该被作为垃圾收集之后,在对象的内存被实际回收之前,会调用这个虚方法。需要在垃圾回收之前执行一些清理工作的类型应该重写这个方法。第21章“自动内存管理(垃圾回收)” 会更详细地讨论这个重要的方法

  CLR要求所有对象都用new操作符来创建。下面这行代码展示了如果创建一个Employee对象:

  Employee e = new Employee(“ConstructorParam1”);

  以下是new操作符所作的事情:

  1. 它计算类型及其所有基类型(一直到System.Object,虽然它没有定义自己的实例字段)中定义的所有实例字段需要的字节数。堆上的每个对象都需要一些额外的成员—即“对象类型指针”(type object pointer)和“同步块索引”(sync block index)。这些成员由CLR用于管理对象。这些额外成员的字节数会计入对象大小。
  2. 它从托管堆中分配指定类型要求的字节数,从而分配对象的内存,分配的所有字节都设为零(0)。
  3. 它初始化对象的“类型对象指针”和“同步块索引”成员。
  4. 调用类型的实例构造器,向其传入在对new的调用中指定的任何实参(上例就是字符串”ConstructorParam1”)。大多数编译器都在构造函数中自动生成代码来调用一个基类构造器。每个类型的构造器在调用时,都要负责初始化由这个类型定义的实例字段。最终调用的是System.Object的构造器,该构造器只是简单地返回,不会做其他任何事情。为了证明这一点,可使用ILDasm.exe加载MSCorLib.dll,自己检查System.Object的构造器方法。

  new执行了所有这些操作之后,会返回指向新建对象一个引用(或指针)。在前面的示例代码中,这个引用会保存到变量e中,后者具有Employee类型。

  顺便说一句,没有和new操作符对应的一个delete操作符;换言之,没有办法显式释放一个对象分配的内存。CLR采用了垃圾回收机制(详情在第21章讲述),能自动检测到一个对象不再被使用或访问,并自动释放对象的内存。