之前的内容已经提到了静态方法。在JAVA中被静态修饰过的成员依然可以通过实例来调用,但是在C#中,静态成员仅可以通过类来调用。其实我们通常声明的时候,都在使用了C#中默认的关键字Auto,只不过没有显式写出而已,当类定义了一个非静态的数据时,这个类型的每一个对象都保存着一份私有副本。Auto是由程序自 动控制变量的生存周期,通常指的就是变量在进入其作用域(一般是由大括号控制)的时候被分配,离开其作用域的时候被释放;而static是变量在程序初始化时被分配,直到程序退出前才被释放;也就是说static是按照程序的生命周期来分配释放变量的,而不是变量自己的生命周期。如果是下面的代码:
class MyClass { int num1=0; static int num2=0; public void SomeMethod() { num1++; num2++; Console.WriteLine("num1为{0},num2为{1}",num1,num2); } } |
class Program { static void Main(string[] args) { MyClass m1 = new MyClass ();m1. SomeMethod (); MyClass m2 = new MyClass ();m2. SomeMethod (); MyClass m3 = new MyClass ();m3. SomeMethod (); Console.ReadLine(); } } |
1.6.1
结果如下:
num1为1,num2为1 num1为1,num2为2 num1为1,num2为3 |
程序在每次创建对象并调用这个方法时,num1都是新的,初始值都为0,因为它是在作用域开始时创建,结束时释放的。而num2就表现的十分镇静,每次累加都是在之前的基础之上累加,所以可以得出不管是否使用变量num2,它在程序初始化时已经分配了,或者是在第一次声明时就已经被分配了,所以无论怎么使用,指向的都是同一块内存空间的内容。
6.2 静态构造函数
前面提到过构造函数一般是用来做初始化的,但是假如我们在构造函数中给静态数据进行了初始化,那么虽然静态数据仅建立一次,但是在每次构造新对象时总会被还原成初始值。比如:
class MyClass { int num1 = 0; static int num2 ; public MyClass() {//实例构造函数 num2 = 0; } public void SomeMethod() { num1++; num2++; Console.WriteLine("num1为{0},num2为{1}", num1, num2); } } |
// Program类代码与1.6.1相同 |
1.6.2
结果如下:
num1为1,num2为1 num1为1,num2为1 num1为1,num2为1 |
如果想要通过其他方式(比如读取数据库或文件)将信息保存进静态数据中,以便之后使用,又仅想保证只在第一次创建对象时对其初始化的话,就必须考虑使用静态构造函数。于是将代码修改如下:
class MyClass { int num1 = 0; static int num2 ; static MyClass() {//静态构造函数 num2 = 0; } public void SomeMethod() { num1++; num2++; Console.WriteLine("num1为{0},num2为{1}", num1, num2); } } |
// Program类代码与1.6.1相同 |
1.6.3
结果如下:
num1为1,num2为1 num1为1,num2为2 num1为1,num2为3 |
这样就可以达到前面所说的目的。还有一些需要注意的:
静态构造函数 |
一个给定的类(或结构)只能定义一个静态构造函数 |
静态构造函数仅执行一次,与创建了多少个这种类型的对象无关 |
静态构造函数不带访问修饰符,也不能带任何参数 |
静态构造函数创建类实例时,或在调用者访问第一个静态成员之前,运行库会调用静态构造函数 |
静态构造函数在任何实例级别的构造函数之前运行 |
1.6.4
6.3 静态类
我们知道,在一个类中是可以出现静态成员和非静态成员的,而静态成员不允许通过类的实例来调用,这也许会让使用者有一些头疼,到底是应该如何调用呢?如果习惯了JAVA开发的程序员,会在实例化类后找不到所需的静态数据。于是在C# 2005后引入了静态类(static class)这个概念。被static修饰过的类只允许包含静态成员或常量数据,并且此类不允许使用NEW关键字来创建。
static class MyClass { const double PI = 3.14; static string name = "Mgod"; static MyClass() { }//静态构造函数,编译通过 private static void SomeMethod1() { }//通过 int num = 20;//报错,不能在静态类中声明实例成员 private void SomeMethod2() { }//报错,不能在静态类中拥有非静态成员 public MyClass(){}//报错,因为静态类不允许有实例构造函数 } |
1.6.5
使用静态类更为简洁和安全,因为它限制了此类中必须拥有什么样类型的成员。更好理解