
上一篇我们彻底掌握了面向对象三大核心特性:封装、继承、多态,学会了通过类封装数据、通过继承复用代码、通过多态实现灵活拓展。
我们之前写的所有字段、属性、方法,都属于实例成员,必须实例化对象后才能调用。但在实际项目开发中,有很多通用工具方法、全局共享数据、固定不变的常量,根本不需要反复 new 对象。
这就引出了C#开发中最容易混淆、面试必考、项目必用 的核心知识点:静态成员、静态类、const常量、readonly只读。
很多新手写代码多年,依然分不清:静态和实例到底有什么区别?const和readonly看着一样为什么不能混用?什么时候用静态类、什么时候用普通类?
本篇从零拆解所有核心概念,搭配可落地实战代码,彻底扫清这块知识盲区,补齐面向对象的最后一块核心短板。
一、前置核心:实例 vs 静态(本质区别)
在学习具体语法前,我们先搞懂最核心的底层逻辑,这是所有知识点的基础。
1. 实例成员(之前所学全部内容)
我们之前写的普通属性、普通方法,都属于实例成员。
-
归属 :归属于 对象,不归属于类
-
调用方式 :必须
new 类名()实例化对象后调用 -
内存特点:每 new 一个对象,就会开辟一块独立内存,对象之间数据互不干扰
-
场景:每个对象独有、独立的数据和行为(学生姓名、年龄、学习行为)
2. 静态成员(本篇核心)
被 static 修饰的成员,统称为静态成员。
-
归属 :归属于 类,不归属于任何对象
-
调用方式 :直接
类名.成员名调用,无需 new 对象 -
内存特点:全局唯一,整个程序运行期间只开辟一块内存,所有对象共享同一份数据
-
场景:全局共享数据、通用工具方法、统计计数
3. 一句话总结
实例成员:每个对象各有一份,互不干扰;静态成员:整个类只有一份,全员共享。
二、静态成员:静态字段与静态方法
1. 静态字段(static 字段)
普通字段是对象独有,静态字段是类共享,适合存储全局公共数据、统计数据。我们用「学生人数统计」实战演示,这是静态字段最经典的应用场景。
csharp
using System;
class Student
{
// 实例属性:每个学生独有
public string Name { get; set; }
public int Age { get; set; }
// 静态字段:全局共享,统计学生总人数
public static int TotalCount = 0;
// 构造函数:每创建一个学生,人数+1
public Student(string name, int age)
{
Name = name;
Age = age;
// 所有对象共享同一个静态字段
TotalCount++;
}
}
class Program
{
static void Main()
{
// 创建多个学生对象
Student s1 = new Student("张三", 18);
Student s2 = new Student("李四", 19);
Student s3 = new Student("王五", 18);
// 直接通过类名调用静态字段
Console.WriteLine($"当前学生总人数:{Student.TotalCount}");
}
}
运行结果:当前学生总人数:3
可以清晰看出:多个对象共用同一个静态字段,实现了全局统计效果,这是实例字段完全做不到的。
2. 静态方法(static 方法)
被 static 修饰的方法,无需实例化,直接类名调用,核心场景:通用工具方法(数学计算、格式转换、数据校验)。
⚠️ 核心规则(必考):
-
静态方法中 只能直接访问静态成员
-
静态方法中 不能直接访问实例成员(必须实例化对象后才能访问)
-
实例方法中 可以直接访问静态成员
csharp
using System;
// 通用工具类
class MathTool
{
// 静态方法:计算两数之和
public static int GetSum(int a, int b)
{
return a + b;
}
// 静态方法:计算平方
public static int GetSquare(int num)
{
return num * num;
}
}
class Program
{
static void Main()
{
// 无需new对象,直接类名调用
Console.WriteLine($"10+20={MathTool.GetSum(10, 20)}");
Console.WriteLine($"10的平方={MathTool.GetSquare(10)}");
}
}
三、静态构造函数(特殊核心语法)
静态构造函数是新手最容易懵的知识点,它和实例构造函数完全不同,专门用来初始化静态成员。
1. 静态构造函数特性(必记)
-
无访问修饰符、无参数
-
一个类 只能有一个 静态构造函数
-
程序运行中 只会执行一次,在第一次使用类时自动触发
-
优先级高于实例构造函数,优先执行
2. 实战演示
csharp
using System;
class Test
{
public static string Msg;
// 静态构造函数:初始化静态数据
static Test()
{
Msg = "静态数据初始化完成";
Console.WriteLine("静态构造函数执行!");
}
// 实例构造函数
public Test()
{
Console.WriteLine("实例构造函数执行!");
}
}
class Program
{
static void Main()
{
// 第一次使用类,触发静态构造函数
Console.WriteLine(Test.Msg);
// 多次实例化,静态构造函数不再执行
Test t1 = new Test();
Test t2 = new Test();
}
}
执行顺序:静态构造函数 → 输出信息 → 两次实例构造函数
四、静态类(static class)
被 static 修饰的类,即为静态类,项目中专门用来写工具类、帮助类。
1. 静态类核心特性
-
只能包含静态成员,不能有实例成员
-
禁止实例化,不能 new 对象
-
程序加载时自动初始化,全局可调用
2. 实战标准工具类(项目常用模板)
csharp
using System;
// 静态工具类:全部为通用静态方法
static class StringTool
{
// 字符串判空
public static bool IsEmpty(string str)
{
return string.IsNullOrEmpty(str);
}
// 反转字符串
public static string ReverseStr(string str)
{
char[] chars = str.ToCharArray();
Array.Reverse(chars);
return new string(chars);
}
}
class Program
{
static void Main()
{
string test = "C#零基础";
Console.WriteLine(StringTool.IsEmpty(test));
Console.WriteLine(StringTool.ReverseStr(test));
}
}
项目中所有工具方法(数据校验、格式处理、算法封装),统一放在静态类中,是企业开发规范。
五、常量 const 与 只读 readonly(高频混淆点)
很多新手分不清 const 和 readonly,二者都是「只读不可修改」,但底层机制、使用场景完全不同,是面试和项目的高频考点。
1. const 常量(编译时常量)
-
本质:编译期常量,程序编译时就确定值,不可修改
-
修饰 :默认是 静态,无需加 static
-
赋值:必须在定义时直接赋值,不能延迟赋值
-
场景:全局固定不变的数值(圆周率、版本号、状态码)
2. readonly 只读(运行时常量)
-
本质:运行时常量,程序运行时确定值,赋值后不可修改
-
修饰:属于实例成员(可搭配static变为静态只读)
-
赋值:可以定义时赋值,也可以在构造函数中赋值
-
场景:对象初始化时确定、后续永不修改的数据
3. 代码对比实战
csharp
using System;
class Config
{
// const 编译时常量:定义必须赋值,全局静态只读
public const double PI = 3.1415926;
// readonly 实例只读字段:可在构造函数赋值
public readonly string Version;
public Config()
{
// 允许在构造函数赋值
Version = "V1.0.0";
// 报错!const 不能在构造函数赋值
// PI = 3.14;
}
}
class Program
{
static void Main()
{
// const 直接类名调用
Console.WriteLine(Config.PI);
Config cfg = new Config();
Console.WriteLine(cfg.Version);
// 报错!只读/常量禁止二次赋值
// cfg.Version = "V2.0";
// Config.PI = 3.15;
}
}
4. 核心取舍规则
-
固定死的数值(永不改变):用 const
-
运行时确定、后续不变的数值:用 readonly
六、全文整合实战案例
整合静态类、静态成员、常量、只读,实现一个简易项目配置工具,完全贴合企业开发场景:
csharp
using System;
// 全局静态配置工具类
static class AppConfig
{
// 常量:固定项目版本
public const string ProjectName = "C#零基础教程";
// 静态只读:运行时初始化
public static readonly string RunTime;
// 静态构造函数:初始化静态数据
static AppConfig()
{
RunTime = DateTime.Now.ToString("yyyy-MM-dd");
}
// 静态工具方法:打印配置信息
public static void PrintConfig()
{
Console.WriteLine($"项目名称:{ProjectName}");
Console.WriteLine($"启动时间:{RunTime}");
}
}
class Program
{
static void Main()
{
// 直接调用静态类方法
AppConfig.PrintConfig();
}
}
七、新手高频易错坑点(必避)
-
静态方法不能调用实例成员:静态属于类,实例属于对象,生命周期不同,禁止直接调用;
-
静态构造函数只会执行一次:无论实例化多少次对象,静态构造函数仅首次加载类时执行;
-
静态类不能实例化:静态类专为工具方法设计,不需要 new 对象;
-
const必须当场赋值:编译时常量不支持构造函数延迟赋值,readonly支持;
-
静态数据全局共享:多对象修改同一个静态字段,会互相影响,慎用静态存储可变数据。
八、全文核心总结
-
实例成员:归属于对象,每个对象独立,必须 new 调用;
-
静态成员:归属于类,全局共享,直接类名调用,适合工具方法、全局统计;
-
静态类:专门存放通用工具方法,禁止实例化,是项目开发标准工具类写法;
-
const常量:编译期固定值,全局静态,适合固定参数;
-
readonly只读:运行时赋值,赋值后不可修改,适合动态初始化的固定数据。
静态与实例的区分、常量与只读的使用,是后续学习框架开发、工具封装、多线程的基础,务必吃透。
下期预告
下一篇我们将精讲 C# 委托与事件,这是C#独有的核心高级特性,是Unity游戏开发、窗体事件编程、框架解耦的核心关键,零基础也能轻松听懂!