|
|
@@ -0,0 +1,303 @@
|
|
|
+# JavaSE 基础 — Day09 笔记
|
|
|
+
|
|
|
+> **日期**:2026-07-23
|
|
|
+> **项目**:`c260723`
|
|
|
+> **作者**:WanJL
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 一、抽象类(Abstract Class)
|
|
|
+
|
|
|
+### 1. 抽象类的引出
|
|
|
+
|
|
|
+**文件**:`Demo01.java`
|
|
|
+
|
|
|
+在父子类继承时,提取子类的共性功能时,有些方法在父类中并没有具体的实现。
|
|
|
+
|
|
|
+例如员工体系:
|
|
|
+
|
|
|
+```
|
|
|
+员工类
|
|
|
+ |- 开发工程师
|
|
|
+ |- Java开发工程师
|
|
|
+ |- 前端开发工程师
|
|
|
+ |- 测试工程师
|
|
|
+ |- 后端测试工程师
|
|
|
+ |- IOS测试工程师
|
|
|
+```
|
|
|
+
|
|
|
+每一个子类的工作内容都是不一样的,所以都需要重写父类的 `work()` 方法,导致父类的 `work()` 方法代码没有实际作用。
|
|
|
+
|
|
|
+```java
|
|
|
+public class 员工 {
|
|
|
+ public void work() {
|
|
|
+ // 每一个子类的工作内容都不一样,此方法体没有意义
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+在 Java 中,一个没有方法体的方法,应该定义为 **抽象方法**;如果类中包含抽象方法,那么这个类必须是 **抽象类**。
|
|
|
+
|
|
|
+### 2. 抽象类的定义
|
|
|
+
|
|
|
+**文件**:`Demo01.java`
|
|
|
+
|
|
|
+使用 `abstract` 关键字来定义抽象类和抽象方法。
|
|
|
+
|
|
|
+**定义抽象类**:
|
|
|
+```java
|
|
|
+public abstract class 类名 {
|
|
|
+ // 成员
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**定义抽象方法**:
|
|
|
+```java
|
|
|
+public abstract 返回值类型 方法名(参数列表);
|
|
|
+```
|
|
|
+
|
|
|
+> **注意**:抽象方法没有方法体(没有 `{}`,直接以分号结尾)。
|
|
|
+
|
|
|
+### 3. 抽象类的特点
|
|
|
+
|
|
|
+**文件**:`Demo01.java`
|
|
|
+
|
|
|
+| 特性 | 说明 |
|
|
|
+|------|------|
|
|
|
+| **关键字** | 抽象类和抽象方法必须使用 `abstract` 关键字修饰 |
|
|
|
+| **抽象方法所在类** | 有抽象方法的类必须是抽象类 |
|
|
|
+| **抽象类中的抽象方法** | 抽象类中不一定要有抽象方法,但抽象方法必须在抽象类中 |
|
|
|
+| **实例化** | **抽象类不能实例化(不能创建对象)** |
|
|
|
+| **构造方法** | 抽象类可以有构造方法(供子类通过 `super()` 调用) |
|
|
|
+| **子类选择** | ① 重写父类所有的抽象方法;② 子类也是抽象类,直接继承父类的抽象方法 |
|
|
|
+| **继承关系** | 抽象父类和具体子类之间是继承关系,子类仍然属于父类类型 |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 二、抽象类代码示例
|
|
|
+
|
|
|
+### 示例 1:动物体系(Animal → Cat / Dog)
|
|
|
+
|
|
|
+#### 抽象父类 Animal
|
|
|
+
|
|
|
+**文件**:`Animal.java`
|
|
|
+
|
|
|
+```java
|
|
|
+package course;
|
|
|
+
|
|
|
+public abstract class Animal {
|
|
|
+ public Animal() {
|
|
|
+ System.out.println("调用动物的构造方法....");
|
|
|
+ }
|
|
|
+
|
|
|
+ public abstract void eat();
|
|
|
+ public abstract void sleep();
|
|
|
+ public abstract void move();
|
|
|
+ public abstract void play();
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+- 定义了 4 个抽象方法:`eat()`、`sleep()`、`move()`、`play()`
|
|
|
+- 包含一个构造方法,虽然抽象类不能直接创建对象,但构造方法可以通过子类 `super()` 调用
|
|
|
+
|
|
|
+#### 子类 Cat
|
|
|
+
|
|
|
+**文件**:`Cat.java`
|
|
|
+
|
|
|
+```java
|
|
|
+package course;
|
|
|
+
|
|
|
+public class Cat extends Animal {
|
|
|
+ @Override
|
|
|
+ public void eat() {
|
|
|
+ System.out.println("猫吃鱼");
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void sleep() {
|
|
|
+ // 空实现
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void move() {
|
|
|
+ // 空实现
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void play() {
|
|
|
+ // 空实现
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+- 使用 `extends` 继承抽象类 `Animal`
|
|
|
+- 使用 `@Override` 注解重写父类的所有抽象方法(必须全部重写,否则子类也要声明为抽象类)
|
|
|
+
|
|
|
+#### 子类 Dog
|
|
|
+
|
|
|
+**文件**:`Dog.java`
|
|
|
+
|
|
|
+```java
|
|
|
+package course;
|
|
|
+
|
|
|
+public class Dog extends Animal {
|
|
|
+ public void eat() {
|
|
|
+ System.out.println("狗吃肉");
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void sleep() { }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void move() { }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void play() { }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+- 同样继承 `Animal`,重写所有抽象方法
|
|
|
+- `eat()` 方法没有写 `@Override` 注解,但仍然是对父类抽象方法的重写(注解只是编译检查,不写也能重写)
|
|
|
+
|
|
|
+#### 测试类 Test01
|
|
|
+
|
|
|
+**文件**:`Test01.java`
|
|
|
+
|
|
|
+```java
|
|
|
+package course;
|
|
|
+
|
|
|
+public class Test01 {
|
|
|
+ public static void main(String[] args) {
|
|
|
+ Dog dog = new Dog();
|
|
|
+ dog.eat(); // 输出:狗吃肉
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+- 创建 `Dog` 对象,调用重写后的 `eat()` 方法
|
|
|
+- 验证了抽象类的子类可以正常创建对象和使用成员方法
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 示例 2:员工体系(Emp → javaEmp)
|
|
|
+
|
|
|
+#### 抽象父类 Emp
|
|
|
+
|
|
|
+**文件**:`Emp.java`
|
|
|
+
|
|
|
+```java
|
|
|
+package course;
|
|
|
+
|
|
|
+// 有抽象方法的类必须是抽象类
|
|
|
+public abstract class Emp {
|
|
|
+ /**
|
|
|
+ * 抽象方法——没有方法体
|
|
|
+ */
|
|
|
+ public abstract void work();
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+- 只定义了一个抽象方法 `work()`
|
|
|
+- 类必须使用 `abstract` 修饰
|
|
|
+
|
|
|
+#### 子类 javaEmp
|
|
|
+
|
|
|
+**文件**:`javaEmp.java`
|
|
|
+
|
|
|
+```java
|
|
|
+package course;
|
|
|
+
|
|
|
+public class javaEmp extends Emp {
|
|
|
+ @Override
|
|
|
+ public void work() {
|
|
|
+ System.out.println("Java开发工程师在开发Java项目");
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+- 重写父类的 `work()` 抽象方法,给出具体的实现
|
|
|
+- 不同子类可以提供不同的实现(例如还可以有 `前端开发工程师`、`后端测试工程师` 等)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 示例 3:服务层体系(BaseService → UserService)
|
|
|
+
|
|
|
+#### 抽象父类 BaseService
|
|
|
+
|
|
|
+**文件**:`BaseService.java`
|
|
|
+
|
|
|
+```java
|
|
|
+package course;
|
|
|
+
|
|
|
+public abstract class BaseService {
|
|
|
+ public abstract void add();
|
|
|
+ public abstract void remove();
|
|
|
+ public abstract void update();
|
|
|
+ public abstract void query();
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+- 定义了标准的 CRUD(增删改查)四个抽象方法
|
|
|
+- 在实际项目中常用来定义业务层接口规范
|
|
|
+
|
|
|
+#### 子类 UserService
|
|
|
+
|
|
|
+**文件**:`UserService.java`
|
|
|
+
|
|
|
+```java
|
|
|
+package course;
|
|
|
+
|
|
|
+public class UserService extends BaseService {
|
|
|
+ @Override
|
|
|
+ public void add() { }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void remove() { }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void update() { }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void query() { }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+- 重写父类的所有抽象方法
|
|
|
+- 方法体暂时为空,后续可添加具体的业务逻辑
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 三、随堂练习要点
|
|
|
+
|
|
|
+**练习目标**:理解抽象类的定义和使用
|
|
|
+
|
|
|
+1. **定义抽象父类**:使用 `public abstract class` 声明,定义抽象方法时不要写方法体
|
|
|
+2. **实现具体子类**:使用 `extends` 继承抽象类,使用 `@Override` 重写所有抽象方法
|
|
|
+3. **测试类验证**:创建子类对象,调用重写后的方法验证正确性
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 四、面试常见问题
|
|
|
+
|
|
|
+**Q1:抽象类能不能被实例化?**
|
|
|
+> 不能。抽象类不能直接 `new` 创建对象。
|
|
|
+
|
|
|
+**Q2:抽象类中一定要有抽象方法吗?**
|
|
|
+> 不一定。抽象类中可以没有抽象方法,但有抽象方法的类必须是抽象类。
|
|
|
+
|
|
|
+**Q3:抽象类的子类必须重写所有抽象方法吗?**
|
|
|
+> 不一定。子类有两个选择:① 重写父类所有抽象方法变为具体子类;② 子类也声明为抽象类,继承父类的抽象方法。
|
|
|
+
|
|
|
+**Q4:抽象类可以有构造方法吗?**
|
|
|
+> 可以。虽然抽象类不能直接创建对象,但其构造方法可以在子类实例化时通过 `super()` 调用,用于初始化父类成员。
|
|
|
+
|
|
|
+**Q5:`abstract` 和 `final` 能否同时修饰一个类或方法?**
|
|
|
+> 不能。`abstract` 表示需要被继承/重写,`final` 表示不能被继承/重写,二者语义冲突。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 五、拓展阅读
|
|
|
+
|
|
|
+- [Java 抽象类(Oracle 官方文档)](https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html)
|
|
|
+- 抽象类 vs 接口(Interface)的区别(将在后续课程中讲解)
|
|
|
+- 模板方法设计模式(Template Method Pattern)—— 抽象类的经典应用场景
|