以前对静态的了解只停留在语法、使用方式上面,今天看了《你必须了解的.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模式的体现