一、核心本质区别(必考简答题)
1. 非静态成员(实例成员)
归属:对象(实例)
每 new 一个对象,就会产生独立的一份数据,对象之间互不干扰。
包含:非静态字段、非静态属性、非静态方法
2. 静态成员(static)
归属:类
全局只有唯一一份数据 ,所有对象共享同一份静态数据
无论 new 多少个对象,静态成员永远只有一份
包含:静态字段、静态属性、静态方法
二、调用规则(超级重点,考试必坑)
1. 非静态成员调用
必须通过 对象名 调用
People p1 = new People();
p1.F1(); // 非静态方法
p1.Id = 1; // 非静态属性
2. 静态成员调用
必须通过 类名 调用(不推荐对象调用,规范写法)
People.Age = 10; // 静态属性
People.F2(); // 静态方法
三、互相访问权限(死规则,必须背死)
1. 非静态方法【可以随便访问】静态成员
非静态方法中,可以直接使用静态属性、静态方法
原因:类静态数据全局常驻,对象实例可以读取类的数据
public void F1()
{
Age = 10; // 直接访问静态属性
F2(); // 直接访问静态方法
}
2. 静态方法【不能直接访问】非静态成员
静态方法中,不允许直接调用非静态属性/方法
原因:静态属于类,对象可能还没创建,没有实例数据
如果一定要用:必须手动 new 对象调用
public static void F2()
{
// 错误:直接使用非静态成员
// Id = 1;
// F1();
// 正确:new 对象后使用
People p = new People();
p.Id = 1;
p.F1();
}
四、属性赋值死循环坑(你代码重点易错点)
错误写法(致命报错)
set
{
Id = value; // 死循环!!
}
原因:Id=value 是属性赋值,会重复触发set访问器,无限递归死循环
正确写法
set
{
Console.WriteLine("ssssssssss");
id = value; // 给私有字段赋值,不触发set
}
口诀:属性set内部,只能给字段赋值,不能给属性赋值
五、静态/非静态 数据独立性代码演示
非静态属性:每个对象独立数据
People p1 = new People();
p1.AddNum(); // p1.Num = 1
People p2 = new People();
p2.AddNum(); // p2.Num = 1
// 输出都是1,互不影响
Console.WriteLine(p1.GetNum());
Console.WriteLine(p2.GetNum());
非静态:一人一份,各自独立
如果是静态属性:所有对象共享一份数据
p1修改静态值 → p2读取到的也是修改后的值
静态:一改全改,全局共享
六、终极对比总表(默写满分)
| 对比维度 | 非静态(实例)成员 | 静态(static)成员 |
|---|---|---|
| 归属 | 属于对象 | 属于类 |
| 调用方式 | 对象名.成员 | 类名.成员 |
| 数据存储 | 每个对象独立一份数据 | 全局唯一一份,所有对象共享 |
| 访问权限 | 可直接访问静态成员 | 不可直接访问非静态,需new对象 |
| 创建时机 | new对象后产生 | 类加载时就存在 |
七、考前终极口诀
-
静态归类不归对象,全局共享只一份
-
非静归对象,每个实例独自享
-
非静可直接用静态,静态想用非静必须new
-
属性set赋值给字段,千万别写属性死循环
八、简答题标准答案
1. 静态成员和非静态成员的区别?
静态成员属于类,全局唯一、所有对象共享一份数据,通过类名调用;非静态成员属于对象,每个对象拥有独立数据,通过对象调用。非静态方法可以直接访问静态成员,静态方法不能直接访问非静态成员,需要实例化对象才可访问。
const常量 / readonly / static readonly 三者终极区别
一、三种只读修饰符 代码对应定义
// 1. 普通只读(实例只读)
public readonly int a = 10;
// 2. 静态只读
public static readonly int b = 20;
// 3. 常量
public const int c = 30;
二、逐条语法规则(必考)
1. const 常量
-
默认自带 static,属于类
-
必须在定义时直接赋值,不能不赋值
-
任何位置都不能修改(构造函数也不能改)
-
调用方式:类名.常量名
-
编译阶段直接固定值,不可变动
2. readonly 实例只读
-
属于对象(实例)
-
可以定义时赋值
-
只能在【无参/有参实例构造函数】中修改一次
-
构造函数执行完毕后,彻底禁止修改
-
不能在静态构造函数修改
3. static readonly 静态只读
-
属于类
-
可以定义时赋值
-
只能在【静态构造函数】中修改
-
绝对不能在普通实例构造函数修改
-
全局唯一、所有对象共享
三、你代码中的执行逻辑精讲
public readonly int a = 10;
public static readonly int b = 20;
public const int c = 30;
// 实例构造
public People()
{
a =20; // 正确:实例只读只能在这里改
// b = 30; // 报错!静态只读不能在实例构造修改
}
// 静态构造
static People()
{
b = 40; // 正确:静态只读只能在这里改
}
执行顺序与结果
-
程序触发类使用 → 静态构造函数先执行 → b=40
-
new 对象 → 实例构造执行 → a=20
-
输出结果: 40---------------- 静态构造函数只能被调用一次... 20++++++++++++ 40 30
四、修改权限禁区(超级易错)
| 类型 | 定义赋值 | 实例构造修改 | 静态构造修改 | 程序运行中修改 |
|---|---|---|---|---|
| const 常量 | 必须赋值 | ❌ 不能改 | ❌ 不能改 | ❌ 完全不能改 |
| readonly 实例只读 | 可选 | ✅ 可改一次 | ❌ 不能改 | ❌ 不能改 |
| static readonly 静态只读 | 可选 | ❌ 不能改 | ✅ 可改一次 | ❌ 不能改 |
五、调用方式区别
-
readonly :对象调用
p1.a -
static readonly :类名调用
People.b -
const :类名调用
People.c
六、三者终极区别(简答题满分)
1. const 常量
编译期常量,默认静态,定义时必须赋值,任何位置不可修改,性能最高。
2. readonly 实例只读字段
属于对象,仅可在实例构造函数中赋值修改一次,运行期只读,不同对象可以有不同数值。
3. static readonly 静态只读字段
属于类,仅可在静态构造函数中赋值修改一次,全局所有对象共享同一个值。
七、满分背诵口诀
-
const 常量编译定,全程谁都不能动
-
readonly 对象只读,实例构造唯一动
-
static readonly 类只读,静态构造改一次
-
构造结束全锁死,运行期间不许动