【C#语言规范版本5.0学习】1.5类和对象(一)
类 (class) 是最基础的 C# 类型。
类是一个数据结构,将状态(字段)和操作(方法和其他函数成员)组合在一个单元中。
类为动态创建的类实例 (instance) 提供了定义,实例也称为对象 (object)。
类支持继承 (inheritance) 和多态性 (polymorphism),这是派生类 (derived class) 可用来扩展和专用化基类 (base class) 的机制。
使用类声明可以创建新的类。类声明以一个声明头开始,其组成方式如下:先指定类的特性和修饰符, 然后是类的名称,接着是基类(如有)以及该类实现的接口。声明头后面跟着类体,它由一组位于一对 大括号 { 和 } 之间的成员声明组成。
下面是一个名为 Point 的简单类的声明:
public class Point { public int x, y; public Point(int x, int y) {
this.x = x; this.y = y; } }
类的实例使用 new 运算符创建,该运算符为新的实例分配内存、调用构造函数初始化该实例,并返回对该实例的引用。
下面的语句创建两个 Point 对象,并将对这两个对象的引用存储在两个变量中:
Point p1 = new Point(0, 0);
Point p2 = new Point(10, 20);
当不再使用对象时,该对象占用的内存将自动收回。在 C# 中,没有必要也不可能显式释放分配给对象的内存。
➤成 员
类的成员分为静态成员 (static member)、实例成员 (instance member)。
下表提供了类所能包含的成员种类的概述
➤可访问性
类的每个成员都有关联的可访问性,它控制能够访问该成员的程序文本区域。有五种可能的可访问性形式。下表概述了这些可访问性。
➤类型形参
类定义可以通过在类名后添加用尖括号括起来的类型参数名称列表来指定一组类型参数。类型参数可用于在类声明体中定义类的成员。
在下面的示例中,Pair 的类型参数为 TFirst 和 TSecond:
public class Pair<TFirst,TSecond> { public TFirst First; public TSecond Second; }
要声明为采用类型参数的类类型称为泛型类类型。结构类型、接口类型和委托类型也可以是泛型。
当使用泛型类时,必须为每个类型参数提供类型实参:
Pair<int,string> pair = new Pair<int,string> { First = 1, Second = “two” }; int i = pair.First; // TFirst is int string s = pair.Second; // TSecond is string
提供了类型实参的泛型类型(例如上面的 Pair<int,string>)称为构造的类型。
➤基 类
类声明可通过在类名和类型参数后面添加一个冒号和基类的名称来指定一个基类。省略基类的指定等同于从类型 object 派生。
在下面的示例中,Point3D 的基类是 Point,而 Point 的基类是 object:
public class Point { public int x, y; public Point(int x, int y) { this.x = x; this.y = y; } } public class Point3D: Point { public int z; public Point3D(int x, int y, int z): base(x, y) { this.z = z; } }
类继承其基类的成员。继承意味着一个类隐式地将它的基类的所有成员当作自已的成员,但基类的实例构造函数、静态构造函数和析构函数除外。
派生类能够在继承基类的基础上添加新的成员,但是它不能移除继承成员的定义。
在前面的示例中,Point3D 从 Point 继承了 x 和 y 字段,并且每个 Point3D 实例均包含三个字段:x、y 和 z。
从某个类类型到它的任何基类类型存在隐式的转换。因此,类类型的变量可以引用该类的实例或任何派生类的实例。
例如,对于前面给定的类声明,Point 类型的变量既可以引用 Point 也可以引用Point3D:
Point a = new Point(10, 20);
Point b = new Point3D(10, 20, 30);
➤字 段
字段是与类或类的实例关联的变量。
使用 static 修饰符声明的字段定义了一个静态字段 (static field)。
一个静态字段只标识一个存储位置。 无论对一个类创建多少个实例,它的静态字段永远都只有一个副本。
不使用 static 修饰符声明的字段定义了一个实例字段 (instance field)。类的每个实例都为该类的所有实例字段包含一个单独副本。
在下面的示例中,Color 类的每个实例都有实例字段 r、g 和 b 的单独副本,但是 Black、White、Red、 Green 和 Blue 静态字段只存在一个副本:
public class Color { public static readonly Color Black = new Color(0, 0, 0); public static readonly Color White = new Color(255, 255, 255); public static readonly Color Red = new Color(255, 0, 0); public static readonly Color Green = new Color(0, 255, 0); public static readonly Color Blue = new Color(0, 0, 255); private byte r, g, b; public Color(byte r, byte g, byte b) { this.r = r; this.g = g; this.b = b; } }
如上面的示例所示,可以使用 readonly 修饰符声明只读字段 (read-only field)。给 readonly 字段的赋值只能作为字段声明的组成部分出现,或在同一个类中的构造函数中出现。
➤方 法
方法 (method) 是一种成员,用于实现可由对象或类执行的计算或操作。
静态方法 (static method) 通过类来访问。
实例方法 (instance method) 通过类的实例来访问。
方法具有一个参数 (parameter) 列表(可以为空),表示传递给该方法的值或变量引用;
方法还具有一个返回类型 (return type),指定该方法计算和返回的值的类型。如果方法不返回值,则其返回类型为 void。
与类型一样,方法也可以有一组类型参数,当调用方法时必须为类型参数指定类型实参。与类型不同的是,类型实参经常可以从方法调用的实参推断出,而无需显式指定。
方法的签名 (signature) 在声明该方法的类中必须唯一。方法的签名由方法的名称、类型参数的数目以及该方法的参数的数目、修饰符和类型组成。方法的签名不包含返回类型。
➤其他函数成员
包含可执行代码的成员统称为类的函数成员 (function member)。
以上描述的方法是函数成员的主要类型。本模块阐述 C# 支持的其他类型的函数成员:构造函数、属性、索引器、事件、运算符和析构函数。
下表演示一个名为 List 的泛型类,它实现一个可增长的对象列表。该类包含了几种最常见的函数成员的示例。
public class List<T> { const int defaultCapacity = 4; //常量 T[] items; int count; //字段 //构造函数 public List(int capacity = defaultCapacity) { items = new T[capacity]; } //属性 public int Count { get { return count; } } public int Capacity { get { return items.Length; } set { if (value < count) value = count; if (value != items.Length) { T[] newItems = new T[value]; Array.Copy(items, 0, newItems, 0, count); items = newItems; } } } //索引器 public T this[int index] { get { return items[index]; } set { items[index] = value; OnChanged(); } } //方法 public void Add(T item) { if (count == Capacity) Capacity = count * 2; items[count] = item; count++; OnChanged(); } protected virtual void OnChanged() { if (Changed != null) Changed(this, EventArgs.Empty); } public override bool Equals(object other) { return Equals(this, other as List<T>); } static bool Equals(List<T> a, List<T> b) { if (a.count != b.count) return false; for (int i = 0; i < a.count; i++) { if (!object.Equals(a.items[i], b.items[i])) { return false; } } return true; } public event EventHandler Changed; //事件 //运算符 public static bool operator ==(List<T> a, List<T> b) { return Equals(a, b); } public static bool operator !=(List<T> a, List<T> b) { return !Equals(a, b); } }