《Beginning c# Objects》读书笔记系列
前面讨论的方法,atrribute和property都与一个类的实体相关联.每个对象都有这些特征的一份拷贝,并且能独立于其他对象操作他们.不过,有时候我们也会许哟啊一个对于类的所有实体都通用的特征.换言之,与其让每个对象拥有该特性的一份拷贝,不如有一个其值为给定类所对象共享的attribute.C#语言通过静态特征来满足这一需求,静态特征与做为一个整体的类相关,而不是与单独的对象相关联.
1.静态attribute
前面已经学过,创建一个类的实体,该类的attribute随后就用该对象特定的值填充.
假设有一些总体信息----如在校学生总数----是我们虚妄所有Student对象能够共享的.我们可以用Student类的一个简单attribute int totalStudents和操作该attribute的代码来实现,如下所示:
publicclass Student{
private int totalStudents;
//等等
//property.
public int TotalStudents{
// 访问器细节从略
}
public int ReportTotalEnrollment(){
Console.WriteLine("Total Enrollment:"+TotalStudents);
}
public void IncrementEncrollment()
TotalStudents = TotalStudents+1;
}
//等等
}
这样做缺乏效率,原因有二.
*首先,每个对象都要重复同样的信息.虽然一个整型(int)变量不讳占有很多内存,但这仍然是一种浪费.除了存储空间考虑之外,我们使用对象技术的任务之一,就是尽可能避免数据/代码冗余.
*二,也是值得关注的一点,当每个新的Student对象被创建时,都得调用系统中每个Student对象的IncrementEnrollment方法,确保所有的Student对象获知新的Student总数,这太让人厌烦了
好在还有一种简单的解决方案!利用static关键字,我们可以把totalStudents设计为Student类的静态attribute:
//totalStudents 被声明为静态attribute.
private static int totalStudents;
//细节从略
public int ReportTotalEnrollment(){
Console.WriteLine("Toal Enrollment:" + TotalStudents);
}
public void IncrementEnrollment(){
totalStudents = totalStudents + 1;
}
}
静态attribute的值做为一个类的所有实体共享 ;在概念上,它的值属于类所有,而不是类的没个实体所有.
每个Student对象都能访问和修改共享的totalStudents attribute,就象它是非共享的attribute一样;早前面的代码例子中,ReportTotalEnroment和IncrementEnrollment方法操作totalStudents attribute是,看来和Student类的其他方法没有区别.不同之处在于,静态attribute的值是共享的,所以如果我们执行下面的客户代码:
s1.Name = "Fred";
s1.IncrementEnrollment();
//此时totalStudents = 1
Student s2 = new Student();
s2.Name = "Mary";
s2.IncrementEnrollment();
//此时totalStudents = 2
Student s3 = new Student();
s3.Name = "Steve";
s3.IncrementEnrollment();
//此时的totalStudents = 3
//在此之后,如果其中任何一个对象检查totalStudents的值,都会得到3.也就是说,我们调用s1、s2、s3的ReportTotalEnrollment方法得到的结果是一样的:每个方法调用的输出信息都会相同。
2.静态的property
我们多半将静态的attribute totalStudents声明为私有(和其他attribue一样),为它编写公共访问器和使用static关键字声明静态attribute不同,静态property和非静态的property没什么不同:
public class Student
private static int totalStudents;
//细节从略
//为静态attribute声明公共静态property
public static int TotalStudent{
get {
return totalStudents;
}
set {
totalStudents = value ;
}
}
//细节从略.
public void IncrementEnrollment() {
//现在可以使用取值/附值访问器了
//注意下面代码中使用了答谢字母T
TotalStudents = TotalStudents + 1;
}
}静态property不能通过单个对象访问,但可以使用点符号,功过整个类调用:
Console.WriteLine("Total Enrollment = "+Student.TotalStudents);
如果试图错误的通过对象调用一个静态property:
Student s1 = new Student();
Console.WriteLine("Total Enrollment = "+ s1.TotalStudents); 编译器会报错
3.静态方法
静态attribute/property与类想关联,而不是关联到具体的耽搁对象:同样,静态方法(staticmethod)也可以通过作为整体的类来调用.
声明一个静态方法:
public static void IncrementEnrollment(){
//和非静态方法相比,方法体没有变化
TotalStudents = TotalStudents + 1;
}
4.静态方法的限制
*它们不能访问类的非静态attribute;
*不能被派生类覆载,所以不可以给静态方法加上virtual关键字;
*静态方法也不能被声明为抽象方法
5.C#特定术语
为了区分静态attribute和非静态attribute,C#使用以下术语:
*实体变量(instance variable)表示一个非静态attribute,因为这样的attribute拥有一个实体或一个对象的值
*静态变量(static variable)表示一个静态attribute
术语本地变量(local variable) 表示一个在方法内部声明的变量,所以只能在方法内部访问.本地变量即不是静态变量也不是实体变量
下面代码展示了三种变量:
//Attributes.
private string name;//实体变量
private static int totalStudentCounr;//静态变量
//方法
public void SomeMethod(int x){//X是一个本地变量
bool //y也是一个本地变量
//等等
}
//等等
}
6.用具类
如我们所了解的,静态方法用于提供独立于任何特定对象之外的普遍功能.例如,我们使用这样的用法
Console.WriteLine(string expression);
来控制显示文本.Console是.NET Framework类库(在System名称空间中) 定义的一个类,WriteLine是该类的一个静态方法.这样,我们不必实体化一个Console对象,就能在屏幕上显示文本;只要通过作为整体Console类调用WriteLine方法就好了.
预定义类的另一个例子是Math类(也在System名称空间中),它完全由静态方法和公共静态attribute组成.
*Mate类声明了多个静态方法,计算三角,指数,对数,幂,还声明了计算数值和产生随机数的方法.
*数字常数e和p声明为Math类的公共静态attribute,分别命名为Math.E和Math.PI;
Console.WriteLint("The value of pi =" + MathPI);
我们非正式的把这样的类称做用具类(utility class)
7.用户自定义用具类
我们可以用同样的技术创建自己的用具类.例如,假定我们经常需要做华氏和摄氏的换算,就可以创建一个用具类(utility class):
pubulic class Temperture{
public static double FahrenheiToCentigrade(double tempF) {
double tempC=(tempF - 32)*(5.0/9.0);
return tempC;
}
public static double CentigradeToFahrenheit(double tempC) {
double fempF = tempC * (9.0/5.0)+32..;
return tempF;
}
}
在可户代码中可以简单地使用这个类:
double temp1 = 212.0;
double temp2 = Temperature.Fahrenheittocentigrade(temp1)
Console.WriteLine(""+temp1+"gegrees F=" + temp2 + "degree C");
结果输出如下:
212.0 degrees F = 100.0 degrees C
我们甚至可能会希望在用具类里面放进一些公用的不变的值----例如冰点
//添加了一些静态attribute/
public static double FahrenheitFreezing = 32.0;
public static doublke CentigradeFreezing 0.0;
public static double FahrenheiBoiling = 212.0;
public static double CentigradeBoiling = 100.0;
pubulic class Temperture{
public static double FahrenheiToCentigrade(double tempF) {
double tempC=(tempF - 32)*(5.0/9.0);
return tempC;
}
public static double CentigradeToFahrenheit(double tempC) {
double fempF = tempC * (9.0/5.0)+32..;
return tempF;
}
}
//同样客户可以在代码中使用这些不变的值:
double soupTemperature;
//已经给soupTemperature 覆值
细节从略if (soupTemperature >=TemperaturelFahrenheitBoilling){
}只有一个小问题:我们希望这些"不变的"值必须真的不会变,但是他们被声明为公共(静态)attribute,谁也栏不住客户修改他们的值:
Temperature.FahreheiBolling = 98.6;//老天
好在我们可以利用一种特殊的变量类型来防止这种情况发生,这种特殊变量就是常量(constant).
8.常量
常量是一种给定初始值后就不会变化的变量.我们使用const关键字来声明常量,如下所示:
public const double FahrenheitFreezing = 32.0;
*常量隐含地是静态的,所以不应给常量的声明加上static关键字,否则编译器会报错
*声明常量时必须给定一个值;即,不能在声明常量后又在程序的其他位置修改它的值
*常数的命名约定是使用Pascal命名风格.
让我们用常量attribute来补充Temperature类:
//添加了一些静态attribute/
public const double FahrenheitFreezing = 32.0;
public const double CentigradeFreezing 0.0;
public const double FahrenheiBoiling = 212.0;
public const double CentigradeBoiling = 100.0;
pubulic class Temperture{
public static double FahrenheiToCentigrade(double tempF) {
double tempC=(tempF - 32)*(5.0/9.0);
return tempC;
}
public static double CentigradeToFahrenheit(double tempC) {
double fempF = tempC * (9.0/5.0)+32..;
return tempF;
}
}
关于常量的其他注意事项如下:
*给常量赋的值必须是在编译时可计算的表达式:
//这行可以被编译过
public const int ImportantConstant = 123+ 456;
//这行不行
public const double AnotherConstant = Math.Sqrt(2.0);
上面的代码片段中,第二个常量生命不能通过编译,因为Math.Sqrt是一个方法,只能在运行时调用
*常量的类型必须是预定义数值类型(char int couble byte 等等) 或string 类型
*也可以在方法中声明一个本地常量:
{
//细节从略
public void Somemethod(){
int x;
const int y = 7 ;
//等等
}
}

浙公网安备 33010602011771号