面向对象的三大特性(封装、继承、多态)核心是让代码更安全、更复用、更灵活,下面用「大白话 + 生活例子 + 极简代码」讲解,每个例子都能直接在 C# 控制台程序中运行。
一、封装:藏细节、露接口,保护数据安全
通俗解释
把对象的内部数据(属性) 和操作数据的方法 打包在一起,将核心细节(比如私有属性)隐藏起来,不让外部代码随便修改 / 访问,只提供指定的公共接口 供外部使用,同时可以在接口中做数据校验,避免无效 / 错误数据。简单说:不让别人乱改你的东西,要改也得按你的规矩来。
生活例子
手机就是封装的典型:你不用知道内部的电路板、芯片怎么工作(隐藏细节),只需要用屏幕、按键、充电口这些公共接口(暴露方法)就能使用,而且手机会自己保护内部零件,不会让你随便拆改。
C# 代码示例(核心:private 私有 + public 公共接口 / 属性)
cs
using System;
// 封装的Person类:藏起内部的age,只露公共接口Age供访问/修改
public class Person
{
// 私有属性:内部细节,外部代码无法直接访问/修改(藏细节)
private int _age;
// 公共属性:外部唯一的访问接口,带数据校验(露接口)
public int Age
{
get { return _age; } // 读接口:获取年龄
set
{
// 数据校验:年龄不能小于0,避免无效数据
if (value >= 0)
_age = value;
else
Console.WriteLine("年龄不能为负数,赋值失败!");
}
}
// 公共方法:外部可调用的行为
public void SayHello()
{
Console.WriteLine($"大家好,我今年{_age}岁!");
}
}
// 测试类
class Program
{
static void Main(string[] args)
{
Person p = new Person();
// 1. 按规矩修改:赋值有效数据(通过公共接口)
p.Age = 20;
p.SayHello(); // 输出:大家好,我今年20岁!
// 2. 尝试乱改:赋值无效数据(接口会校验并拒绝)
p.Age = -5; // 输出:年龄不能为负数,赋值失败!
p.SayHello(); // 输出:大家好,我今年20岁!(年龄未被修改)
// 3. 错误写法:外部无法直接访问私有属性_age(编译器会报错)
// p._age = 30; // 取消注释会提示:无法访问私有字段"_age"
}
}
代码关键说明
private int _age:私有字段,是类的内部细节,外部代码直接访问会编译报错,实现了 "隐藏";public int Age:公共属性,是外部访问_age的唯一接口 ,get用于读取、set用于修改,且set中加了年龄校验,保证数据有效性;- 封装的核心实现:访问修饰符 (
private/public/protected等),其中private是封装的关键。
二、继承:子承父业,复用代码 + 扩展功能
通俗解释
一个类(子类 / 派生类 )可以继承另一个类(父类 / 基类 )的非私有成员 (属性、方法),子类不用重复写父类的代码,直接 "继承使用",同时还能添加自己独有的属性 / 方法,实现功能扩展。简单说:儿子继承父亲的家产和技能,还能自己学新技能。
生活例子
学生(Student)和老师(Teacher)都是 "人(Person)":人有姓名、年龄,会说话;学生继承了人的所有特征,还多了 "学号",会 "学习";老师也继承了人的所有特征,还多了 "工号",会 "教书"------ 不用给学生和老师重复写 "姓名、年龄、说话" 的代码。
C# 代码示例(核心:: 继承符号,单继承)
C# 中类是单继承 (一个子类只能直接继承一个父类),下面基于上面封装的Person类做扩展(直接复用父类的Age、SayHello):
cs
using System;
// 父类/基类:人(已封装)
public class Person
{
private int _age;
public int Age
{
get { return _age; }
set { if (value >= 0) _age = value; }
}
// 新增公共属性:姓名(供子类继承)
public string Name { get; set; }
public void SayHello()
{
Console.WriteLine($"我是{Name},今年{_age}岁!");
}
}
// 子类/派生类:学生,继承Person类(核心:Person前面的冒号)
public class Student : Person
{
// 子类独有的属性:父类没有,扩展功能
public string StudentId { get; set; }
// 子类独有的方法:父类没有,扩展行为
public void Study()
{
Console.WriteLine($"我是学生{Name},学号{StudentId},正在学习C#!");
}
}
// 测试类
class Program
{
static void Main(string[] args)
{
Student s = new Student();
// 继承父类的属性:直接使用,不用重新定义
s.Name = "小明";
s.Age = 18;
// 继承父类的方法:直接调用
s.SayHello(); // 输出:我是小明,今年18岁!
// 子类独有的属性和方法:扩展的功能
s.StudentId = "20260126001";
s.Study(); // 输出:我是学生小明,学号20260126001,正在学习C#!
}
}
代码关键说明
- 继承符号:
class 子类 : 父类,比如Student : Person表示 Student 继承 Person; - 成员复用:子类可以直接使用父类的非私有成员 (
public/protected),比如Name、Age、SayHello,无需重复编写; - 功能扩展:子类可以新增自己独有的成员(
StudentId、Study),实现父类的功能延伸; - 注意:父类的
private私有成员(比如_age)子类无法直接访问,只能通过父类的公共接口(比如Age属性)访问。
三、多态:一个接口,多种实现,调用更灵活
通俗解释
同一个方法 / 接口 ,被不同的对象 调用时,会执行不同的逻辑 ,呈现出不同的行为。简单说:同样的一句话,不同的人说出来,做的事不一样。
核心实现前提
- 存在继承关系(子类继承父类);
- 父类中定义虚方法 (
virtual关键字)或抽象方法; - 子类中重写 (
override关键字)父类的虚方法。
生活例子
父类 "人" 有一个 "工作" 方法,子类 "学生" 和 "老师" 都重写了这个方法:调用 "学生的工作方法",执行的是 "学习";调用 "老师的工作方法",执行的是 "教书"------ 同样是 "工作",不同对象的行为不同。
C# 代码示例(核心:virtual 虚方法 + override 重写)
基于前面的Person父类,新增虚方法Work,让Student和Teacher子类分别重写,实现多态:
cs
using System;
// 父类/基类:人
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
// 虚方法:父类定义方法模板,允许子类重写(核心:virtual关键字)
public virtual void Work()
{
Console.WriteLine("人需要工作/学习,实现自身价值!");
}
}
// 子类1:学生,重写父类的Work方法
public class Student : Person
{
public override void Work() // 核心:override关键字重写
{
Console.WriteLine($"学生{Name}的工作:认真听课,完成作业,学习知识!");
}
}
// 子类2:老师,重写父类的Work方法
public class Teacher : Person
{
public override void Work() // 核心:override关键字重写
{
Console.WriteLine($"老师{Name}的工作:认真备课,讲课,批改作业!");
}
}
// 测试类
class Program
{
static void Main(string[] args)
{
// 多态的关键:父类引用 指向 子类对象
Person p1 = new Student();
p1.Name = "小红";
p1.Work(); // 调用的是Student子类的Work方法
Person p2 = new Teacher();
p2.Name = "李老师";
p2.Work(); // 调用的是Teacher子类的Work方法
// 直接实例化父类,调用原始虚方法
Person p3 = new Person();
p3.Work(); // 调用的是Person父类本身的Work方法
}
}
运行结果
学生小红的工作:认真听课,完成作业,学习知识!
老师李老师的工作:认真备课,讲课,批改作业!
人需要工作/学习,实现自身价值!
代码关键说明
- 虚方法:
public virtual void Work(),父类中用virtual标记的方法,表示 "这个方法可以被子类修改 / 重写",自身有默认实现; - 方法重写:子类中用
override标记的方法,必须和父类虚方法的方法名、参数、返回值完全一致,表示 "用子类的逻辑替换父类的默认逻辑"; - 多态核心:父类引用指向子类对象 (
Person p1 = new Student()),此时调用方法时,程序会自动识别对象的实际类型(Student/Teacher),执行对应的重写方法,而非父类的原始方法; - 灵活性:如果后续新增一个 "医生" 子类,只需要继承
Person并重写Work方法,无需修改原有代码,符合面向对象的 "开闭原则"。
三大特性核心总结
- 封装 :用
private藏细节、public露接口,保护数据,避免外部乱改(核心:访问修饰符); - 继承 :用
:实现子承父业,复用父类代码,子类可新增成员扩展功能(C# 类支持单继承); - 多态 :用
virtual+override实现 "一个接口多种实现",让代码更灵活,父类引用可适配不同子类对象。
三个特性相互配合:封装是基础(保证数据安全),继承是前提(实现代码复用和扩展),多态是延伸(让扩展后的代码更灵活易维护)。