一、面向对象与面向过程的核心区别(概念铺垫)
代码背景
开篇对比了两种编程范式:
面向过程(PP):按步骤分解问题(如 “输入长→输入宽→计算面积”);
面向对象(OOP):将问题抽象为 “对象”,通过对象的属性和行为解决问题(如 “矩形对象” 有长、宽属性和计算面积的方法)。
补充知识点
编程范式:是解决问题的 “方法论”,OOP 更适合复杂系统(可维护性、复用性强),PP 适合简单流程(如脚本工具)。
对象的核心特征:状态(属性) 和行为(方法) 的封装。例如 “人” 的属性是姓名、年龄,行为是吃饭、睡觉。
二、类与对象的基础定义(Rectangle 类示例)
代码解析
class Rectangle // 类定义 {public int Length; // 属性(字段)public int Width; public int Area() // 方法{return Length * Width;} } // 实例化对象并使用 Rectangle rectangle = new Rectangle(); rectangle.Length = 5; rectangle.Width = 3; Console.WriteLine(rectangle.Area()); // 输出15
补充知识点
类的本质:“模板” 或 “蓝图”,定义对象的 “能有什么”(属性)和 “能做什么”(方法)。
对象的实例化:
new 类名()
是创建对象的语法,本质是在内存中分配空间,初始化属性。成员访问:通过
对象.成员
访问属性或调用方法,体现对象的 “自主性”。
三、类的创建与结构(People 类示例)
代码解析
class People // 类定义(默认internal修饰符) {string name; // 私有字段(默认private)int age; void eat() // 私有方法{Console.WriteLine("吃饭");} }
补充知识点
类的结构三要素:
字段(成员变量):存储对象的状态(如
name
、age
);方法:定义对象的行为(如
eat()
);访问修饰符:控制成员的可访问范围(核心是封装)。
访问修饰符作用:
public
:任何地方可访问(如对外暴露的接口);private
:仅类内部可访问(如内部计算的临时变量);internal
:仅当前项目可访问(如项目内共享的工具类)。
访问修饰符 / 范围 | 当前类 | 父类 | 实例对象 | 引用当前项目的项目子类 | 引用当前项目实例对象 | 同一程序集的非子类 | 不同程序集的子类 | 不同程序集的非子类 |
---|---|---|---|---|---|---|---|---|
public | √ | √ | √ | √ | √ | √ | √ | √ |
private | √ | × | × | × | × | × | × | × |
internal | √ | √ | √ | √ | √ | √ | × | × |
protected | √ | √ | × | √ | × | × | √ | × |
protected internal | √ | √ | × | √ | √ | √ | √ | × |
private protected | √ | × | × | √ (仅同一程序集) | × | × | × (不同程序集) | × |
四、对象的实例化与成员访问(People 对象示例)
代码解析
// 实例化对象 People p1 = new People(); p1.name = "吴亦凡"; // 访问公共字段(需先将name改为public) // 对象初始化器(语法糖) People p2 = new People() { name = "罗志祥" }; // 调用方法 p1.eat(); People.sleep(); // 调用静态方法
补充知识点
对象初始化器:
new 类名() { 成员 = 值 }
简化对象属性赋值,本质是先调用构造函数,再赋值。静态成员访问:静态方法 / 属性属于类本身(如
People.sleep()
),无需实例化对象,通过类名.成员
访问;非静态成员属于对象(如p1.eat()
),必须通过实例访问。
五、属性与字段的封装(Student、Dog 类示例)
代码解析
class Student {private char _sex; // 私有字段(内部存储)public char Sex // 公共属性(外部访问接口){get { return _sex; } // 获取值set // 设置值(带验证){if (value == '男' || value == '女')_sex = value;elsethrow new Exception("性别必须是男或女");}} }
补充知识点
封装的核心体现:用私有字段存储数据,通过公共属性控制访问,避免外部直接修改导致数据混乱(如年龄不能为负、性别只能是男女)。
属性的访问器:
get
:返回字段值(可添加逻辑,如计算后返回);set
:接收外部传入的value
(需与属性类型一致),可添加验证逻辑。
字段与属性的本质区别:
字段是 “容器”(直接存数据);
属性是 “接口”(不存数据,通过
get/set
操作字段,实现数据保护)。
六、构造函数与对象初始化(People 类构造函数示例)
代码解析
class People {public string Name { get; set; }public int Age { get; set; } // 无参构造函数public People(){Console.WriteLine("无参构造执行");} // 有参构造函数(重载)public People(string name, int age){Name = name;Age = age;} }
补充知识点
构造函数作用:对象实例化时自动执行,用于初始化对象(如设置默认值、验证参数)。
构造函数重载:同一类中多个构造函数,参数列表不同(体现多态),满足不同初始化需求(如无参构造用默认值,有参构造自定义值)。
默认构造函数:若未手动定义构造函数,编译器自动生成无参构造;若定义了有参构造,默认无参构造会被覆盖,需手动添加。
七、析构函数与垃圾回收(People 析构函数示例)
代码解析
class People {~People() // 析构函数{Console.WriteLine("析构函数执行");} } // 触发垃圾回收 People p1 = new People(); p1 = null; // 解除引用 GC.Collect(); // 强制回收
补充知识点
析构函数作用:对象被垃圾回收(GC)时自动执行,用于释放非托管资源(如文件句柄、数据库连接)。
GC 机制:C# 自动管理内存,当对象无引用时,GC 会在合适时机回收内存,析构函数执行时机不可控,因此优先使用
IDisposable
接口手动释放资源。
八、静态成员与实例成员(People 静态成员示例)
代码解析
class People {public string Name1 { get; set; } // 实例属性public static string Name2 { get; set; } // 静态属性 public void Test1() // 实例方法{Console.WriteLine(Name1); // 可访问实例和静态成员Console.WriteLine(Name2);} public static void Test2() // 静态方法{// Console.WriteLine(Name1); 错误:静态方法不能访问实例成员Console.WriteLine(Name2); // 只能访问静态成员} }
补充知识点
静态成员特性:
属于类,所有对象共享一份(如计数器、工具方法);
生命周期与程序一致(程序启动时加载,结束时释放);
静态方法中无
this
指针(因不依赖对象)。
应用场景:工具类(如
Math
)、全局配置(如AppConfig
)、单例模式等。
九、常量与只读成员(Test 类示例)
代码解析
class Test {public const int c = 2; // 常量(编译期确定)public readonly int a = 1; // 只读字段(运行期确定) public Test(){a = 10; // 只读字段可在构造函数中赋值} private string _d = "1";public string D { get => _d; } // 只读属性(无set) }
补充知识点
const 与 readonly 区别:
const
:编译时确定值,必须声明时赋值,可用于字段 / 局部变量;readonly
:运行时确定值,可在声明或构造函数中赋值,仅用于字段。
只读属性:仅保留
get
访问器(如D
),确保属性只能被读取,无法外部修改,增强封装。
十、继承与派生(People→Student→SamllStudent 示例)
代码解析
// 基类 class People {public string Name { get; set; }public void Eat() { Console.WriteLine("吃饭"); } }// 派生类 class Student : People // 继承语法:派生类:基类 {public string StudentId { get; set; } // 新增属性public void Study() { Console.WriteLine("学习"); } }// 继承链:SamllStudent → Student → People → object class SamllStudent : Student { }
补充知识点
继承核心作用:代码复用(子类继承父类所有成员,除构造函数、析构函数)。
C# 继承特性:
单继承:一个类只能直接继承一个基类(避免菱形继承问题);
传递性:
SamllStudent
间接继承People
的成员;向上转型:
People p = new Student()
(子类对象可赋值给父类变量,体现多态)。
十一、作业:Aircraft 类的完整封装(综合应用)
代码核心模块解析
public class Aircraft {// 1. 私有字段(内部存储)private string _brand;private int _loadCapacity; // 最大装载人数private string _aircraftType; // 飞机类型private int _currentLoad; // 当前装载人数// 2. 公共属性(外部访问接口,带验证)public int LoadCapacity{get => _loadCapacity;set{if (value < 0) throw new ArgumentException("最大装载人数不能为负");_loadCapacity = value;CalculateAircraftType(); // 自动计算类型GenerateCurrentLoad(); // 生成当前人数}}public string AircraftType => _aircraftType; // 只读属性// 3. 构造函数(初始化)public Aircraft(string brand, int loadCapacity){_brand = brand;LoadCapacity = loadCapacity; // 触发类型计算}// 4. 私有方法(内部逻辑)private void CalculateAircraftType(){_aircraftType = _loadCapacity > 400 ? "大型" : (_loadCapacity > 200 ? "中型" : "小型");}private void GenerateCurrentLoad(){_currentLoad = new Random().Next(1, _loadCapacity + 1); // 随机生成}// 5. 公共方法(对外行为)public void TakeOff(){Console.WriteLine($"{_brand}起飞,当前装载{_currentLoad}人");} }
知识点综合应用
封装:通过
LoadCapacity
属性的set
访问器验证输入合法性,确保_loadCapacity
不为负。自动逻辑:设置
LoadCapacity
时自动触发CalculateAircraftType
(根据人数分类型)和GenerateCurrentLoad
(随机生成当前人数),体现对象的 “自主性”。只读属性:
AircraftType
仅暴露get
,确保类型由内部逻辑计算,外部无法修改。构造函数:通过有参构造函数初始化核心属性,简化对象创建流程。
总结
面向对象编程的核心是 “抽象” 与 “封装”:通过类抽象事物的共性,通过对象实例化具体事物,通过访问修饰符、属性、方法控制数据和行为的访问,最终实现高内聚、低耦合的代码设计。Aircraft 类综合应用了字段、属性、构造函数、方法等要素,是面向对象思想的典型实践。