C#中的静态与非静态
为什么要分静态和非静态 在面向对象的世界里,大部分的情况都是实例特征主宰天下,类相当于一个类型模板,而对象则是类特征的拷贝,并且独立于其他对象来操作这些特征,但是在某些情况下,需要某些特征被所有的对象共公有,因此有必要实现一种基于类的特征,而不是基于实例对象的特征机制,这就是静态特征。 1.静态类和非静态类 一个类如果包含静态成员和静态方法,那么该类就可以定义为静态类,定义方法是在类定义前加上static,比如 static class MyClass { //define the class } 比较: 静态类只能包含静态成员和静态方法,否则会抛出编译错误,而非静态类既可以包含非静态成员和非静态方法,还可以包含静态成员和静态方法。但不能作用于静态只读字段。 静态类不可实例化,非静态类可以实例化,不管是静态类还是非静态类,对静态成员和静态方法的调用都必须通过类来实现访问。 相对于非静态类来说,静态类有一些特点值得应用,比如System.Console这个典型的静态类。 如果一个类只包含静态成员和静态方法,就应该将该类标记为static,并提供私有的构造函数来避免用户实例创建对象,这也是MonoState模式的体现。 2.静态构造函数和实例构造函数 静态构造函数,只能用于初始化类中的静态成员,包括静态字段和静态属性,静态构造函数不能带参数,不能有访问修饰符也不能被手工调用,通过是在.net运行库第一次调用类成员之前执行。其中,实例构造函数中也是可以初始化静态成员的。 比较 静态构造函数,可以和无参的构造函数共存。虽然参数列表相同,但是二者的执行顺序不同,静态构造函数在运行库加载类时执行,而实例构造函数在实例创建时执行。 静态构造函数,只能对静态成员进行初始化操作,不能作用于非静态成员,而实例构造函数二者都可以,当然如前面所说,对静态只读字段就不可以了。 静态构造函数只被执行一次,而且.net运行库也不知道什么时候会被执行,而实例构造函数可以在多次实例创建时被执行多次。 一个类只能有一个静态构造函数,但是可以有多个实例构造函数。 一般来说,简单的静态成员可以在声明时就进行初始化,而复杂的静态成员则选择在静态构造函数中进行初始化较佳。 3.静态成员和实例成员 静态成员主要包括静态字段和静态属性,静态成员可以实现在类中能够被所有实例对象共享的数据。例如一个缴费登记系统中,消费总额作为所以消费的综合,静态成员来实现就有很好。没有不必要的数据冗余。 比较 静态成员包括静态字段和静态属性,静态字段一般实现为private,而静态属性一般为public,以体现类的封装原则。 静态成员和类关联,不依赖对象存在,只能由类访问,而不能由对象访问,实例成员和具体的对象关联,只能由对象访问,不能由类访问。 静态成员属于类所有,不论创建多少个实例对象,静态成员在内存中只有一份,实例成员属于对象实例所有,每个都有其对应的内存区域。 4.静态方法和实例方法 类似于静态成员共享数据段,静态方法共享代码段,静态方法以static标识。 比较 性能上,静态方法和实例方法差别不大,所有方法,不管是静态的还是非静态的,都是在JIT加载类时分配内存,不同的是静态方法以类名引用,而静态方法以对象引用,创建实例时,不会再为类的方法分配内存,所有的实例对象公用一个类的方法代码,因此,静态方法和实例方法的调用,区别仅在于实例方法需要当前对象指针指向该方法,而静态方法可以直接调用,性能上差异微乎其微。 静态方法只能访问静态成员和静态方法,可以间接通过创建实例对象来访问实例成员和实例方法,而实例方法可以直接全部。。 静态方法只能由类来访问,实例方法只能由对象来访问。 静态方法中不能使用this关键字,否则编译错误,而实例方法中可以引用。 静态方法不能被标记为virtual,abstract或是override,静态方法可以被派生类访问,但是不能被覆写。 Main方法是静态的,因此Main方法不能直接访问Main所在类的实例方法和成员。 鉴于线程处理的安全性,应该避免提供改变静态状态的静态方法,因为,如果多线程同时访问该段代码,可能造成线程处理错误,因此,静态状态必须是线程安全的。 静态方法适合系统中边缘性的非业务需要,例如通用的工具类。