静态类
继承(多态)、静态本身就是相反的。另外需要知道属性、事件其实是些特殊的方法。
使用 static 修饰符声明属于类型本身而不是属于特定对象的静态成员。 static 修饰符可用于类、字段、方法、属性、运算符、事件和构造函数,但不能用于索引器、析构函数或类以外的类型。
静态类与非静态类基本相同,但存在一个区别:静态类不能实例化。 也就是说,不能使用 new 关键字创建静态类类型的变量。 因为没有实例变量,所以要使用类名本身访问静态类的成员
对于 只对输入参数进行运算 而不获取或设置 任何内部实例字段的方法集,静态类可以方便地用作这些方法集的容器。 例如,在 .NET Framework 类库中,静态类 System.Math 包含的方法只执行数学运算,而无需存储或检索特定 Math 类实例特有的数据。 就是说,通过指定类名称和方法名称来应用类成员。
和所有类类型一样,当加载引用静态类的程序时,.NET Framework 公共语言运行时 (CLR) 将加载该静态类的类型信息。程序不能指定加载静态类的确切时间。 但是,可以保证在程序中首次引用该类前加载该类,并初始化该类的字段并调用其静态构造函数。 静态构造函数仅调用一次,在程序驻留的应用程序域的生存期内,静态类一直保留在内存中。
下表介绍静态类的主要特性:
- 仅包含静态成员。
- 无法实例化。
- 是密封的。
- 不能包含实例构造函数。
因此,创建静态类与创建仅包含静态成员和私有构造函数的类基本相同。 私有构造函数阻止类被实例化。使用静态类的优点在于,编译器能够执行检查以确保不致偶然地添加实例成员。编译器将保证不会创建此类的实例。
静态类是密封的,因此不可被继承。 它们不能从除 Object 外的任何类中继承。 静态类不能包含实例构造函数,但可以包含静态构造函数。 如果非静态类包含需要进行重要的初始化的静态成员,也应定义静态构造函数。
静态类构造函数
静态构造函数用于初始化任何 静态 数据,或用于执行仅需执行一次的特定操作。 在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数。
例如:
class SimpleClass
{ static readonly long baseline;
static SimpleClass()
{ baseline = DateTime.Now.Ticks; }
}
静态构造函数具有以下特点:
- 静态构造函数既没有访问修饰符,也没有参数。
- 在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数来初始化类。
- 无法直接调用静态构造函数。
- 在程序中,用户无法控制何时执行静态构造函数。
- 静态构造函数的典型用途是:当类使用日志文件时,将使用这种构造函数向日志文件中写入项。
- 静态构造函数在为非托管代码创建包装类时也很有用,此时该构造函数可以调用 LoadLibrary 方法。
- 如果静态构造函数引发异常,运行时将不会再次调用该构造函数,并且在程序运行所在的应用程序域的生存期内,类型将保持未初始化。
静态成员
非静态类可以包含静态的方法、字段、属性或事件。 即使没有创建类的实例,也可以调用该类中的静态成员。 始终通过类名而不是实例名称访问静态成员。 无论对一个类创建多少个实例,它的静态成员都只有一个副本。 静态方法和属性不能访问其包含类型中的非静态字段和事件,并且不能访问任何对象的实例变量(除非在方法参数中显式传递)。
更常见的做法是声明具有一些静态成员的非静态类,而不是将整个类声明为静态类。 静态字段有两个常见的用法:一是记录已实例化对象的个数,二是存储必须在所有实例之间共享的值。
静态方法可以被重载但不能被重写,因为它们属于类,不属于类的任何实例。
虽然字段不能声明为 static const,但 const 字段的行为在本质上是静态的。 这样的字段属于类型,不属于类型的实例。
C# 不支持静态局部变量(在方法范围内声明的变量)。
通过在成员的返回类型之前使用 static 关键字可以声明静态类成员,也就是在方法的返回类型前加static。
静态成员在第一次被访问之前并且在调用静态构造函数(如有存在)之前进行初始化。 若要访问静态类成员,应使用类名而不是变量名来指定该成员的位置。
自问自答,自娱自乐
静态成员与实例成员的性能对比和生成调用指令的差别有哪些?
对静态方法的调用以 Microsoft 中间语言 (MSIL) 生成调用指令,而对实例方法的调用生成 callvirt 指令,该指令还检查 null 对象引用。 但是,两者之间的性能差异在大多数时候并不明显。
为什么静态类不能被继承?
经反编译查看,Static内部是用sealed和abstract两个关键字组合实现的,也就是说没有static这个关键字,只是为了方便区别。
静态类的使用和实例类中静态成员的使用技巧?
对于 只对输入参数进行运算 而不获取或设置 任何内部实例字段的方法集,静态类可以方便地用作这些方法集的容器。也就是说,这个类只是一个工具类,里面都是些方法。
常见的做法是声明具有一些静态成员的非静态类,而不是将整个类声明为静态类。由于无论对一个类创建多少个实例,它的静态成员都只有一个副本,所以静态字段有两个常见的用法:一是记录已实例化对象的个数,二是存储必须在所有实例之间共享的值。
静态类和非静态类之间的包含关系?
非静态类可以包含静态类成员,静态类只能包含静态成员。如下所示:
Static class staticclass{//只能是静态成员};
Class newClass{//可以包含静态成员};
尽管类的实例包含该类所有实例字段的单独副本,但每个静态字段只有一个副本。
静态类成员声明字段的特殊性:
class Test
{ static int x = y;
static int y = 5;
static void Main() {
Console.WriteLine(Test.x);
Console.WriteLine(Test.y);
Test.x = 99;
Console.WriteLine(Test.x);}
}/*Output: 0 5 99 */
什么情况下需要在一个普通类中编写一个静态成员,而这个类不能标记static?
当这个需要被实例化的时候,如果这个类中有一个成员是所有对象都共享的数据,这时可以将该类中的这个成员标记为静态的,但是这个类还是一个实例类。
特别需要注意的有哪些呢?
- 静态成员会在整个应用程序退出时,才释放资源,所以可以在整个应用程序中共享数据。
- 当一个普通类添加静态字段后,系统会默认为该类生成一个静态构造函数【静态构找函数不能有访问修饰符,并且也不能带参数】
- 静态方法可以被重载但不能被重写,因为它们属于类,不属于类的任何实例。
- 不可以使用 this 来引用静态方法或属性访问器。
- 类和静态类可以有静态构造函数。 静态构造函数在程序开始和类实例化之间的某个时刻调用。
- 静态类的本质是abstract+sealed组成。静态类不能被实例化是因为abstract,不能被继承是因为sealed。