1. 为什么需要抽象类?
想象一个场景:我们要定义 “人” 的行为,但 “人” 是个很抽象的概念 —— 学生、老师、医生的工作方式(Work
)不一样,年龄的存储方式也可能不同。这时候,抽象类 可以帮我们:
- 定义 “必须实现的规则”(比如子类必须有
Work
方法和Age
属性),但不写具体实现; - 作为基类,让子类(如
Student
)继承并 “填充” 具体逻辑。
2. 抽象类的核心规则
从代码和规则来看:
- 不能直接创建抽象类的对象:比如
new People()
会报错,因为抽象类是 “半成品”,必须由子类完善。 - 抽象方法 / 属性只能在抽象类里声明:外面不能单独写
abstract void Work()
,必须包在抽象类里。 - 抽象类不能是密封类(
sealed
):密封类不能被继承,而抽象类就是为了被继承设计的,两者矛盾。
3. 代码逐段分析(结合例子)
① 抽象类 People
的定义
public abstract class People
{
// 抽象属性:只有声明,没有具体实现(get/set里没代码)
public abstract int Age { get; set; }
// 抽象方法:只有签名,没有方法体(大括号里没代码)
public abstract void Work();
}
- 抽象属性
Age
:要求子类必须实现 “如何存、如何取” 年龄。 - 抽象方法
Work
:要求子类必须实现 “工作 / 行为” 的具体逻辑。
② 派生类 Student
继承并实现抽象成员
public class Student : People
{
private int studentId;
private string studentName;
private int age; // 用来存储年龄的私有字段
// 重写抽象属性 Age:实现 get 和 set
public override int Age
{
get { return age; } // 取 age 的值
set { age = value; } // 存 value 到 age
}
// 构造函数:初始化学生的学号和姓名
public Student(int id, string name)
{
studentId = id;
studentName = name;
}
// 重写抽象方法 Work:实现具体行为(学生学习)
public override void Work()
{
Console.WriteLine($"编号:{studentId},姓名:{studentName},年龄:{Age} 在学校学习!");
}
}
override
关键字:告诉编译器 “我要重写基类的抽象成员”,必须写,否则报错。- 逻辑关联:
Age
属性操作私有字段age
,Work
方法里通过Age
属性获取年龄,最终输出完整信息。
③ Main 方法里的调用
Student student = new Student(101, "李红"); // 创建 Student 对象(子类可以实例化)
student.Age = 25; // 设置年龄(调用 Age 的 set 方法)
student.Work(); // 调用 Work 方法,输出:编号:101,姓名:李红,年龄:25 在学校学习!
- 因为
Student
是具体类(非抽象),所以必须实现所有抽象成员,才能被实例化。
4. 关键对比:抽象类 vs 普通类
特性 | 抽象类(abstract ) | 普通类 |
---|---|---|
能否实例化 | 不能(new 会报错) | 可以 |
成员类型 | 可以包含抽象成员(无实现) | 必须有完整实现(方法体、属性逻辑) |
继承目的 | 作为基类,让子类实现抽象成员 | 直接使用或被继承 |
5. 常见疑问
-
抽象类里可以有普通方法吗?
可以!比如给People
加一个Sleep()
方法(有具体实现),子类可以直接用,不用重写。抽象类里既可以有抽象成员(强制子类实现),也可以有普通成员(子类直接继承)。 -
如果子类不想实现抽象成员怎么办?
不行!除非子类也声明为abstract
(变成抽象类),否则必须重写所有抽象成员。
6.总结
你可以理解:抽象类是 “模板”,规定了子类必须有的能力,但把具体实现交给子类。就像 “人” 规定了必须会 “工作”、有 “年龄”,但学生的 “工作” 是学习,老师的 “工作” 是教学 —— 各自实现细节不同,但遵循同一套规则。