第7章类和对象 集,, ■7.1类的概念 711类的声明 类由类头和类体两部分组成。声明一个类的格式为: attributes类修饰符clas类名:基类类体 其中 attribute、基类、类体是可选的 ■特性( attribute):是C井新的成分,程序员可以通过系统提供的 System Attributes类来创建类似关键字的描述性声明来解释编程元素,如类型 字段、方法和属性,并附加新的特征。 NET Framework的MS和CLR支持 attribute
第7章 类和对象 7.1.1 类的声明 类由类头和类体两部分组成。声明一个类的格式为: attributes 类修饰符 class 类名 : 基类 类体 其中attribute、基类、类体是可选的。 ◼ 7.1 类的概念 ◼ 特性(attribute):是C#新的成分,程序员可以通过系统提供的 System.Attribute类来创建类似关键字的描述性声明来解释编程元素,如类型、 字段、方法和属性,并附加新的特征。.NET Framework的MSIL和CLR支持 attribute
71.1类的声明 ■类修饰符有: abstract、 public、 protected、 internal、 private、new、 sealed一个类声明可以包含多个类修饰符,但是不能重复 类修饰符: abstract用来指示该类是抽象类,抽象类是一种没有完全实现的 类,它不能产生对象,只能被继承;修饰符 public、 protected、 private、 internal是访问控制符,用来规定外界调用该类成员权限;new用作类修饰 符只能修饰嵌套的类,具有隐藏同名成员的作用; sealed修饰符指出该类 是最终类,即,不能被继承。 class:是关键字,是声明类的必须的符号。 类名:是类设计者指定的标识符。 基类:如果正在定义的类需要从另一个类中继承所有的成员,被继承的 类就是基类,引入基类时,在类名和基类之间加上冒号运算符“:”,接 口也是一种基类。 类体:包括类的数据成员、表现这些成员行为的方法、以及成员的修饰 符,类体中的所有内容置于一对大括号“{”和“}”之间
7.1.1 类的声明 ◼ 类修饰符有:abstract、public、protected、internal、private、new、 sealed。一个类声明可以包含多个类修饰符,但是不能重复。 类修饰符:abstract用来指示该类是抽象类,抽象类是一种没有完全实现的 类,它不能产生对象,只能被继承;修饰符public、protected、private、 internal是访问控制符,用来规定外界调用该类成员权限;new用作类修饰 符只能修饰嵌套的类,具有隐藏同名成员的作用;sealed修饰符指出该类 是最终类,即,不能被继承。 ◼ class:是关键字,是声明类的必须的符号。 ◼ 类名:是类设计者指定的标识符。 ◼ 基类:如果正在定义的类需要从另一个类中继承所有的成员,被继承的 类就是基类,引入基类时,在类名和基类之间加上冒号运算符“:”,接 口也是一种基类。 ◼ 类体:包括类的数据成员、表现这些成员行为的方法、以及成员的修饰 符,类体中的所有内容置于一对大括号“{”和“}”之间
7.12类的成员(1) 集,如 7.1.2.1常量 用 const关键字声明常量的形式为: 修饰符 const类型常量名=常量表达式; 常量字段有如下特点 常量必须在声明的同时初始化,所以常量表达式必须是能 够在编译时计算确定的值 ■常量只能一次赋值,以后不能改变 ■常量的类型可以是简单类型、枚举类型、 string类型和非 string的其它引用类型(但是值只能是nu),结构不能是常 量 常量是隐式的静态成员(但不能用 I static修饰),也就是说, 常量字段属于类而不属于对象,使用常量需要用“类名常量 名”这样的形式
7.1.2 类的成员(1) ◼ 7.1.2.1 常量 用const关键字声明常量的形式为: 修饰符 const 类型 常量名 = 常量表达式; 常量字段有如下特点: ◼ 常量必须在声明的同时初始化,所以常量表达式必须是能 够在编译时计算确定的值 ◼ 常量只能一次赋值,以后不能改变 ◼ 常量的类型可以是简单类型、枚举类型、string类型和非 string的其它引用类型(但是值只能是null),结构不能是常 量 ◼ 常量是隐式的静态成员(但不能用static修饰),也就是说, 常量字段属于类而不属于对象,使用常量需要用“类名.常量 名”这样的形式
7.12类的成员(2) ■7.1.22实例字段和静态字段 C#中有两种字段,属于具体对象的实例字段和属于类的静态字段。 字段默认为实例字段。 假设有一个类X,X中有一个实例字段t,一个静态字段s;从X产 生100个对象,那么每个对象都有一个字段t,存储器中有100个t, 但是100个对象共享1个静态字段s,存储器中只有1个s。 静态字段要用关键字 static声明,例如: static int Tota; 静态字段属于类,所以使用静态字段要用“类名静态字段”这样 的形式。 C#中还有其它静态成员,例如静态方法, static修饰的成分的作用 和用法 静态字段能被静态方法和实例方法所访问
7.1.2 类的成员(2) ◼ 7.1.2.2 实例字段和静态字段 C#中有两种字段,属于具体对象的实例字段和属于类的静态字段。 字段默认为实例字段。 假设有一个类X,X中有一个实例字段t,一个静态字段s;从X产 生100个对象,那么每个对象都有一个字段t,存储器中有100个t, 但是100个对象共享1个静态字段s,存储器中只有1个s。 静态字段要用关键字static声明,例如:static int Total; 静态字段属于类,所以使用静态字段要用“类名.静态字段”这样 的形式。 C#中还有其它静态成员,例如静态方法,static修饰的成分的作用 和用法. 静态字段能被静态方法和实例方法所访问
7.12类的成员(3) ■7.1.2.3只读字段 只读字段用关键字 readonly声明,顾名思义,这样的字段是只可读出,不 可写入的,这一点和常量相同。 对只读字段赋值只能在如下情况下进行: 声明只读字段的同时初始化 ■在构造函数和静态构造函数中初始化 在上述的情况下甚至可以多次赋值,除此以外,只读字段只能读出不能 修改了。也不能将它们用作out参数或者re惨参数。如果只读字段没有初始 化,就自动赋以默认值。 只读字段和常量的差别 只读字段不具备 static特征,只读字段属于实例。 只读字段可以在运行阶段确定值,常量是在编译阶段确定值,因此可以 用变量表达式对只读字段赋值 只读字段可以是任何类型。 const可以修饰局部变量,但 readonly不能修饰局部变量
7.1.2 类的成员(3) ◼ 7.1.2.3 只读字段 只读字段用关键字readonly声明,顾名思义,这样的字段是只可读出,不 可写入的,这一点和常量相同。 对只读字段赋值只能在如下情况下进行: ◼ 声明只读字段的同时初始化 ◼ 在构造函数和静态构造函数中初始化 在上述的情况下甚至可以多次赋值,除此以外,只读字段只能读出不能 修改了。也不能将它们用作out参数或者ref参数。如果只读字段没有初始 化,就自动赋以默认值。 只读字段和常量的差别: ◼ 只读字段不具备static特征,只读字段属于实例。 ◼ 只读字段可以在运行阶段确定值,常量是在编译阶段确定值,因此可以 用变量表达式对只读字段赋值。 ◼ 只读字段可以是任何类型。 ◼ const可以修饰局部变量,但readonly不能修饰局部变量
7.2对象 类中除了常量以外,其它数据成员只有类型,但没有具体的数 据,表现这些数据的行为的方法,也没有用武之地。当类中 的数据有了具体的值以后,就形成了对象,类中的方法也有 了运行的基本条件,所以对象是类的实例。不同的对象具有 不同的对象名和仅仅属于自己的数据。 逻辑上,对象拥有自己定义的数据成员和方法以及所有继承得 到数据成员和方法,但是物理上:对象名是存储在栈中的, 对象的数据是在堆中的,而方法是存放在代码区中的,类的 方法和类在一起,为该类的所有对象共享,这样保证了一个 类的所有对象的行为的一致性。一个对象必须拥有自己的对 象名和数据,但是完全没有必要拥有一份代码的拷贝 个类可以产生许多对象,类的生命期和对象的生命期是不同 的,不同的对象可能有不同的生命期 调用对象的成员的形式为:对象名对象成员
7.2 对象 类中除了常量以外,其它数据成员只有类型,但没有具体的数 据,表现这些数据的行为的方法,也没有用武之地。当类中 的数据有了具体的值以后,就形成了对象,类中的方法也有 了运行的基本条件,所以对象是类的实例。不同的对象具有 不同的对象名和仅仅属于自己的数据。 逻辑上,对象拥有自己定义的数据成员和方法以及所有继承得 到数据成员和方法,但是物理上:对象名是存储在栈中的, 对象的数据是在堆中的,而方法是存放在代码区中的,类的 方法和类在一起,为该类的所有对象共享,这样保证了一个 类的所有对象的行为的一致性。一个对象必须拥有自己的对 象名和数据,但是完全没有必要拥有一份代码的拷贝。 一个类可以产生许多对象,类的生命期和对象的生命期是不同 的,不同的对象可能有不同的生命期。 调用对象的成员的形式为:对象名.对象成员
73构造函数 构造函数又称构造方法,C#的构造函数有两种:实例构造函 数和静态构造函数,实例构造函数初始化对象;而静态构造 函数初始化类,我们平常所说的“构造函数”默认地指实例 构造函数,以后也同样。构造函数的最基本特点是: 构造函数名与类名一样 ■构造函数没有返回类型
7.3 构造函数 构造函数又称构造方法,C#的构造函数有两种:实例构造函 数和静态构造函数,实例构造函数初始化对象;而静态构造 函数初始化类,我们平常所说的“构造函数”默认地指实例 构造函数,以后也同样。构造函数的最基本特点是: ◼ 构造函数名与类名一样 ◼ 构造函数没有返回类型
731创建对象 通常,对象的创建和初始化总是一起完成的。声明对象的格式 如下:类名对象名 声明一个对象就是在栈中为对象名开设空间,而对象名所含的 值,是一个空引用。创建并初始化对象的格式为: 对象名=new类名(初始化参数列表); 注意到,类名和构造函数名是一样的,所以也可以把“类名 (初始化参数列表)”这样的表达式理解为构造函数的调用, 关键字new根据类名和初始化列表创建并初始化了一个对象, new表达式返回这个对象的引用。程序7-1的第二个构造函数 初始化了对象中所有的数据成员,而第一个构造函数没有作 任何初始化工作。在C#中,如果对象的成员没有在构造时被 初始化,那么就被赋以默认值,对象的默认值是空引用 声明并初始化对象的语句格式如下 类名对象名=new构造函数(初始化参数列表)
7.3.1 创建对象 通常,对象的创建和初始化总是一起完成的。声明对象的格式 如下:类名 对象名; 声明一个对象就是在栈中为对象名开设空间,而对象名所含的 值,是一个空引用。创建并初始化对象的格式为: 对象名 = new 类名(初始化参数列表); 注意到,类名和构造函数名是一样的,所以也可以把“类名 (初始化参数列表)”这样的表达式理解为构造函数的调用, 关键字new根据类名和初始化列表创建并初始化了一个对象, new表达式返回这个对象的引用。程序7-1的第二个构造函数 初始化了对象中所有的数据成员,而第一个构造函数没有作 任何初始化工作。在C#中,如果对象的成员没有在构造时被 初始化,那么就被赋以默认值,对象的默认值是空引用。 声明并初始化对象的语句格式如下: 类名 对象名 = new 构造函数(初始化参数列表);
732默认的构造函数 个没有参数没有可执行语句的构造函数,称为默认的构造函 数,或者无参构造函数。创建对象必须要调用构造函数,如 果类中没有定义构造函数的话,系统将自动地调用默认的构 造函数。调用默认的构造函数的结果是创建一个对象,对象 中的数据成员的值为成员的数据类型的默认值。 如果类中没有定义任何构造函数,系统会自动地添加一个 默认的构造函数; 如果类中定义了任何构造函数,系统就不会自动添加默认 的构造函数 默认的构造函数,即无参数无语句的构造函数的形式特别简单: public类名()
7.3.2 默认的构造函数 一个没有参数没有可执行语句的构造函数,称为默认的构造函 数,或者无参构造函数。创建对象必须要调用构造函数,如 果类中没有定义构造函数的话,系统将自动地调用默认的构 造函数。调用默认的构造函数的结果是创建一个对象,对象 中的数据成员的值为成员的数据类型的默认值。 ◼ 如果类中没有定义任何构造函数,系统会自动地添加一个 默认的构造函数; ◼ 如果类中定义了任何构造函数,系统就不会自动添加默认 的构造函数。 默认的构造函数,即无参数无语句的构造函数的形式特别简单: public 类名 ( ) { }
733构造函数的重载 构造函数的重载是常见的现象,同一个类中有多个构造函数, 区分它们的依据是参数列表,同一个类中的任意两个构造函 数的参数列表必须不同,参数列表只有满足下列条件之一, 就可以认为是不同的参数列表,进而可以认为是两个重载的 构造函数 参数列表中参数个数不同; 参数列表中参数个数相同,但参数类型不同 参数列表中参数个数相同,参数类型种类也相同,但是排 列的次序不同 重载的构造函数之间有一种比较特殊的现象,这就是构造函数 调用同类的其它构造函数
7.3.3 构造函数的重载 构造函数的重载是常见的现象,同一个类中有多个构造函数, 区分它们的依据是参数列表,同一个类中的任意两个构造函 数的参数列表必须不同,参数列表只有满足下列条件之一, 就可以认为是不同的参数列表,进而可以认为是两个重载的 构造函数: ◼ 参数列表中参数个数不同; ◼ 参数列表中参数个数相同,但参数类型不同; ◼ 参数列表中参数个数相同,参数类型种类也相同,但是排 列的次序不同。 重载的构造函数之间有一种比较特殊的现象,这就是构造函数 调用同类的其它构造函数