版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34536551/article/details/83957585
目录
先看一个静态字段的示例:
namespace Ch05Ex03
{
class Persion
{
int Mem1;
static int Mem2; //私有静态成员
static Persion()
{
Mem2 = 900;
//Mem1 = 200; //不可以在静态构造函数中初始化 非静态字段
WriteLine("静态构造函数被调用!\n");
}
public Persion(int aa,int bb)
{
Mem1 = aa;
Mem2 = bb; //利用构造函数设置私有静态成员
WriteLine("\n实例构造函数被调用!\n");
}
public void SetVars(int v1,int v2)
{
Mem1 = v1;
Mem2 = v2;
}
public void Display(string str)
{
WriteLine($"{str}: Mem1的值:{Mem1}, Mem2的值:{Mem2}");
}
}
class Program
{
static void Main(string[] args)
{
Persion d1 = new Persion(2, 8); //利用公有构造函数设置静态字段和普通字段的值
d1.Display("d1");
Persion d2 = new Persion(5, 77);
d2.Display("d2");
WriteLine();
d1.SetVars(7, 22); //利用公有成员函数设置静态字段和普通字段的值
d1.Display("d1");
d2.SetVars(99, 100);
d2.Display("d2");
d1.Display("d1"); //这里再次输出d1的值,输出就是 7,100,因为它被d2 改变了
// 注意下面的代码:
Persion d3 = new Persion(141, 55), d4 = new Persion(454, 666);
/*该代码输出:
* d3: Mem1的值:141, Mem2的值:666
d4: Mem1的值:454, Mem2的值:666
为什么d3的值是141和666, 而不是141,55 呢?
首先执行该代码的时候我们调用实例构造函数执行成员初始化,我们首先初始化实例d3的成员,然后设置
d4的成员 ,设置d3的时候我们初始化Mem1为141,Mem2 = 55, 设置d4的值时初始化Mem1为454. Mem2 = 666.
因为静态字段被类的所有实例所共享, 所有实例都访问同一内存位置。因此d4把静态字段Mem2的值改变了,
因此 d3的 Mem2 的值也改变了。*/
d3.Display("d3");
d4.Display("d4");
ReadKey();
}
}
}
输出结果为:
静态构造函数被调用!
实例构造函数被调用!
d1: Mem1的值:2, Mem2的值:8
实例构造函数被调用!
d2: Mem1的值:5, Mem2的值:77
d1: Mem1的值:7, Mem2的值:22
d2: Mem1的值:99, Mem2的值:100
d1: Mem1的值:7, Mem2的值:100
实例构造函数被调用!
实例构造函数被调用!
d3: Mem1的值:141, Mem2的值:666
d4: Mem1的值:454, Mem2的值:666
那为什么没有输出静态构造函数中设置的值呢,道理都是一样的,程序首先调用的就是静态构造函数,调用之后 Mem2 = 900; Mem1=0; 记住: 不管这个类有多少个类实例, 静态构造函数只调用一次。
然后就调用实例构造函数,实例构造函数设置的值直接覆盖了静态构造函数中的值,所以输不出静态构造函数设置的值。
静态成员的生命期
● 只有在实例创建之后才产生实例成员,在实例销毁后实例成员就不存在了。
● 但静态成员,即使类没有实例,也存在静态成员,并且可以访问。(在C++中不可以这样)
namespace Ch05Ex03
{
class D
{
static public int Mem2; //但是如果设置为私有的静态成员,就不可以在类外通过类直接访问
}
class Program
{
static void Main(string[] args)
{
D.Mem2 = 5; //通过类名直接为公有静态数据成员赋值, 但是如果该成员是私有,就不可以这样赋值
WriteLine(D.Mem2);
ReadKey();
}
}
}
输出结果为:
5
注意: 静态成员即使没有类的实例也存在。如果该静态字段有初始化语句,那么会在使用该类的任何静态成员之前初始化该字段, 但没必要在程序执行的开始就初始化。
静态成员函数
● 如同静态字段,静态成员函数独立于任何类实例。 即使没有类的实例,仍然可以调用静态方法。(C++中不可以这样)
● 注意:类成员函数(无论是static成员函数或非static成员函数)都可以直接访问static数据成员,static 成员函数仅能访问static 数据成员,不能访问非static的数据成员,也不能访问非static 的成员函数。
namespace Ch05Ex03
{
class D
{
static public int Mem2;
public int aa = 10; //在类定义中初始化一个非静态的公有成员
static public void PrintVal() //静态成员函数访问静态成员数据
{
WriteLine(Mem2);
//WriteLine(aa); 静态成员不可以访问非静态数据成员
}
public void getVal()
{
WriteLine(aa); // 输出aa的值
WriteLine(Mem2); //非静态函数可以访问静态的数据成员
}
}
class Program
{
static void Main(string[] args)
{
D.Mem2 = 5;
D.PrintVal();
D dd = new D(); // 创建该类的对象
dd.getVal();
ReadKey();
}
}
}
输出结果为:
5
10
5
在C++中可以声明常量为静态的常量成员数据, 而在C#中却不可以。
与C++不同,在C#中没有全局常量。 每个常量都必须声明在类型内。
成员常量
namespace Ch05Ex03
{
class D
{
//用于初始化常量的值必须是在编译时就可以确定的,通常是一个简单类型的值或者一个表达式
const int Mem2 = 5;
const int Mem3 = 2 * Mem2; // 正确, 但是Mem2 必须是一个const字段,否则错误。
}
class Program
{
static void Main(string[] args)
{
ReadKey();
}
}
}
常量与静态量
● 注意: 常量成员即使没有类的实例也可以使用。 与真正的静态量不同, 常量没有自己的存储位置, 而是在编译时被编译器替换。 跟C++中的 #define 类似。
看一个C++的程序:
class D
{
public:
const double PI = 3.14;
D(decltype(PI) aa):PI(aa)
{
}
};
int main()
{
D dd(22.3);
cout << dd.PI << endl;
system("pause");
return 0;
}
看一个C#程序:
namespace Ch05Ex03
{
class D
{
public const double PI = 3.14;
}
class Program
{
static void Main(string[] args)
{
WriteLine(D.PI); //利用类实例访问公有常量数据成员
ReadKey();
}
}
}
在C#中常量成字段现得像一个静态量, 但不能将常量字段声明成 static:
static const double PI = 3.14; //错误
但是在C++中可以。