目录
6.1 类成员
之前的两章阐述了9中类成员类型的两种:字段和方法。在这一章中,我会介绍除事件和运算符之外的类型的类成员,并讨论其特征。我会在14章介绍事件。
表6-1列出了类的成员类型。已经介绍过的类型用菱形标记。将在本章阐述的类型用勾号标记,将在以后的章节阐述的类型用空的选择框标记。
6.2 成员修饰符的顺序
在前面的内容中,你看到字段和方法的声明可以包括public和private这样的修饰符。这一章会讨论许多其他的修饰符。多个修饰符可以在一起使用,自然就产生了一个问题:它们需要按什么顺序排列呢?
类成员声明语句由下部分组成:核心声明、一组可选的修饰符和一组可选的特性(attribute)。用于描述这个结构的语法如下。方括号表示方括号内的成分是可选的。
【特性】【修饰符】 核心声明
- 修饰符
- 如果有修饰符,必须放在核心声明之前。
- 如果有多个修饰符,可以是任意顺序。
- 特性
- 如果有特性,必须放在修饰符和核心声明之前。
- 如果有多个特性,可以是任意顺序。
至此,我直解释两个修饰符,及public和private 。在第24章中我会在介绍特性。
例如,public和static都是修饰符,可以用来一起修饰某个声明。因为它们都是修饰符,所以可以放置成任何顺序。下面两行代码语义等价:
6.3 实例类成员
类成员可以关联到类的一个实例,也可以关联到类的整体,既所有类的实例。默认情况下,成员被关联到一个实例。可以认为是类的每个实例拥有自己的各个类成员的副本,这些成员称为实例成员。
改变一个实例字段的值不会影响任何其他实例中成员的值。迄今为止,你所看到的字段和方法都是实例字段和实例方法。
例如,下面的代码声明了一个类D,它带有唯一整形字段Mem1.Main创建了该类的两个实例,每个实例都有自己的字段Mem1的副本,改变一个实例的字段副本的值不影响其他实例的副本的值。图6-2阐明了类D的两个实例、
6.4 静态字段
除了实例字段,类还可以,拥有静态字段。
- 静态字段被类的所有实例共享,所有实例都访问同一内存位置。因此,如果该内存位置的值被一个实例改变了,这种改变对所有的实例都可见。
- 可以使用static修饰符将字段声明为静态,如:
例如,图6-3左边的代码声明了类D,它含有静态字段Mem2和实例字段Mem1.Main定义了类D的两个实例。该图表明静态成员Mem2是与所有实例存储分开保存的。实例中灰色字段表明。从实例内部,访问或更新静态字段的语法和访问或更新其他成员字段一样。
- 因为Mem2是静态的,类D的两个实例共享单一的Mem2字段。如果Mem2被改变了,这个改变在两个实例中都能看到。
- 成员Mem1没有声明为static,所以每个实例都有自己的副本。
6.5 从类的外部访问静态成员
在前一章中,我们看到使用点运算符可以从类的外部访问public实例成员。点运算符由实例名、点和成员组成。
就像实例成员,静态成员也可以使用点运算符从类的外部访问。但因为没有实例,所以必须使用类名,如下面代码所示:
6.5.1 静态字段实例
下面的代码扩展了前文的类D,增加了两个方法:
- 一个方法设置了两个数据成员的值。
- 另一个方法显示两个数据成员的值。
6.5.2 静态成员的生存期
静态成员的生命周期与实例成员的不同。
- 之前我们已经看到了,只有在实例创建之后才产生实例成员,在实例销毁之后实例成员也就不复存在了。
- 但是即使类没有实例,也存在静态成员,并且可以访问。
6.6 静态函数成员
除了静态字段,还有静态函数成员。
- 如同静态字段,静态函数成员独立与任何类实例。即使没有类的实例,仍然可以调用静态方法。
- 静态函数成员不能访问实例成员。然而它们能访问其他静态成员。
例如,下面的类包含一个静态字段和一个静态方法。注意,静态方法的方法体访问静态字段。
6.7 其他静态类。成员类型
可以声明为static的类成员类型在表6-2中做了勾选标记。其他类型成员不能声明为static。
6.8 成员常量
成员常量类似前一章所述的本地常量,只是它们被声明在类声明中而不是方法内,如下面的实例:
6.9 常量与静态量
然而,成员常量比本地常量更有趣,因为它们表现得像静态值。它们对类的每个实例都是“可见的”,而且即使没有类的实例也可以使用。与真正的静态量不同,常量没有自己存储位置,而是在编译时被编译器替换。这种方式类似于C和C++中的#define值。
例如,下面的代码声明了类X,带有常量字段PI。Main没有创建任何实例,但仍然可以使用字段PI并打印它的值。图6-6阐明了这段代码。
6.10 属性
属性是代表类实例或类中的一个数据项的成员。使用属性看起来非常像写入或读取一个字段,语法是相同的。
例如,下面的代码展示了名称为MyClass的类的使用,它有一个公有字段和一个公有属性。从用法上无法区分它们。
与字段类似,属性有如下特性。
- 它是命名的类成员。
- 它有类型。
- 它可以被赋值和读取。
然而和字段不同,属性是一个函数成员。
- 它不为数据存储分配内存!
- 它执行代码。
属性是定的一组两个匹配的、称为访问器的方法。
- set访问器为属性赋值。
- get访问器从属性获取值。
图6-7展示了属性的表示法。左边的代码展示了声明一个名称为MyValue的int型属性的语法,右边的图像展示了属性在文本中将如何可视化地显示。请注意,访问器被显示为从后面伸出,因为它们不能直接被调用。这一点你很快就会看到。
6.10.1 属性声明和访问器
set和get访问器有预定义的语法和语义。可以把set访问器想象成一个方法,带有单一的参数“设置”属性的值。get访问器没有参数并从属性返回一个值。
- set访问器总是:
- 拥有一个单独的、隐式的值参、名称为value,与属性的类型相同;
- 拥有一个返回类型void。
- get访问器总是:
- 没有参数;
- 拥有一个与属性类型相同的返回类型。
属性声明结构如图6-8所示。注意,图中访问器声明既没有显示的参数,也没有返回类型声明。不需要它们,因为它们已经在属性的类型中隐含了。