以前对静态的了解只停留在语法、使用方式上面,今天看了《你必须了解的.NET》中的:动静之间—静态和非静态和园子里面关于static的一些文章,才对静态有了一个更加深入的了解。
一、静态简介
很多情况下,实例特征主宰天下,类相当于一个特征模板,而对象就是这个模板的拷贝,并且独立于其他对象来操作这些特征。但是,在某些情况下,我们需要某些特征被所有的对象实体共有,因此有必要实现一种基于类的特征,而不是基于实例的特征机制,这就是静态,简单来说就是:一个类的实例共享同一个成员变量。
二、静态的特征
不需要new,直接通过"类名."的方式调用
三、静态成员特征
① 静态字段、属性
//类Consumer public class Consumer { private double cost; public double Cost { get { return cost; } set { cost = value; } } private static double costAll; public static double CostAll { get { return costAll; } set { costAll = value; } } //计算消费总额方法 public void AddCost() { costAll += cost; } //打印消费总额 public void ShowCost() { Console.WriteLine(CostAll); } } //在Main中调用 static void Main(string[] args) { Consumer consumber1 = new Consumer(); consumber1.Cost = 5.25; consumber1.AddCost(); Consumer consumber2 = new Consumer(); consumber2.Cost = 3.23; consumber2.AddCost(); //结果都是8.48 因为输出的都是static值,共享数据的体现 consumber1.ShowCost(); consumber2.ShowCost(); }
总结:(1):不需要再各个类里面都重复同样的数据,从性能上来讲,静态成员避免了不必要的数据
(2):体现了数据共享的机制,同时也避免了以附加操作来处理每个对象都共享的数据信息
(3):静态成员不能被对象调用,只能以"类."的形式进行调用
② 静态方法与实例方法
//类StaticMethodDemo public class StaticMethodDemo { public static string staticString = "static string"; public string noStaticString = "no static string"; //StaticMethod public static void StaticMethod() { //1、静态方法也可以重载 //2、静态成员不能被标记为:virtual,override,abstract //不能直接调用noStaticString通过 实例.noStaticString,不能使用this关键字 Console.WriteLine(staticString); } //noStaticMethod public void NoStaticMethod() { //可以使用this关键字,可以调用静态和非静态成员 Console.WriteLine(this.noStaticString); Console.WriteLine(staticString); Console.WriteLine(noStaticString); } } //派生自StaticMethodDemo的类StaticMethodChildrenDemo public class StaticMethodChildrenDemo:StaticMethodDemo { //具体实现 } //Main static void Main(string[] args) { StaticMethodDemo staticMethodDemo = new StaticMethodDemo(); //只有对象才能调用实例方法,对象无法调用静态成员 staticMethodDemo.NoStaticMethod(); //使用类直接调用静态成员 StaticMethodDemo.StaticMethod(); Console.WriteLine(StaticMethodDemo.staticString); //派生类可以调父类中的静态方法,但是无法重写,因为静态方法无法使用virtual,override,abstract来修饰 StaticMethodChildrenDemo.StaticMethod(); }
总结异同点: (1):静态方法可以重载。静态方法使用类名引用,实例方法使用对象引用
(2):静态方法不能使用virtual,override,abstract来修饰
(3):静态方法内部不能使用this关键字,因为静态成员是类独有的,非静态方法可以
(4):静态方法内部,不能调用非静态成员,但是实例方法中可以调用静态和飞静态成员
(5):派生类可以调用父类中的静态方法,同样是"类名."的方式,对象无法调用静态成员
(6):在性能上,静态方法与实力方法的差别不大,都是在JIT(Just in time即时编译器)类时分配内存,两者的区别仅在于:实例方法需要当前对象指针指向该方法,而静态方法可以直接调用,在性能上差别很小。
③ 静态构造函数和非静态构造函数
public class StaticDemo { public static string staticStr = "Hello"; public int noStaticnumber = 0; public string MyProperty { get; }
//只读的静态字段 public static string MyProperty2 { get; }
//静态只读字段
public static readonly string str; //静态构造函数中不能初始化非静态字段 static StaticDemo() { staticStr = "静态构造方法"; //noStaticnumber = 10; } //能初始化静态字段和非静态方法,但是不能给静态只读字段赋值 public StaticDemo() { staticStr = "构造方法"; noStaticnumber = 1; //通过 MyProperty = "1"; //报错 MyProperty2 = "2"; } }
总结异同点:(1):静态构造函数,可以与无参的实例构造函数同存,但二者的执行时间不同,静态构造函数在运行库加载类的时候被执行,而实例构造函数是类实例化的时候执行,静态构造函数只执行了一次,但是一个类的实例构造函数执行的次数取决于创建对象的次数
(2):静态构造函数,只能对静态成员进行初始化,无法对非静态成员进行初始化。而非静态构造函数两者都可初始化,但是无法初始化只读的静态字段和静态只读字段
图解构造函数的执行顺序
*静态成员的内存分配、成员初始化和构造函数只被执行一次,在JIT编译的时候,下一次创建对象实例的时候,只会执行实例成员的初始化过程
四、总结静态与非静态之间的异同点
(1)、静态类中只能包括静态成员,否则编译器会抛出错误。非静态类中都可以包含。
(2)、静态类不能被实例化,非静态类可以被实例化。但是不管是静态类或是非静态类来说,调用静态成员和静态方法都必须使用类去调用
(3)、System.Console就是一个典型的静态类
(4)、如果一个类中只包含静态成员和静态方法,那么应该把这个类标记为static,并提供私有的构造函数,来避免实例创建,这其实是一种MonoState模式的体现