20260723-笔记.md 7.3 KB

JavaSE 基础 — Day09 笔记

日期:2026-07-23
项目c260723
作者:WanJL


一、抽象类(Abstract Class)

1. 抽象类的引出

文件Demo01.java

在父子类继承时,提取子类的共性功能时,有些方法在父类中并没有具体的实现。

例如员工体系:

员工类
  |- 开发工程师
     |- Java开发工程师
     |- 前端开发工程师
  |- 测试工程师
     |- 后端测试工程师
     |- IOS测试工程师

每一个子类的工作内容都是不一样的,所以都需要重写父类的 work() 方法,导致父类的 work() 方法代码没有实际作用。

public class 员工 {
    public void work() {
        // 每一个子类的工作内容都不一样,此方法体没有意义
    }
}

在 Java 中,一个没有方法体的方法,应该定义为 抽象方法;如果类中包含抽象方法,那么这个类必须是 抽象类

2. 抽象类的定义

文件Demo01.java

使用 abstract 关键字来定义抽象类和抽象方法。

定义抽象类

public abstract class 类名 {
    // 成员
}

定义抽象方法

public abstract 返回值类型 方法名(参数列表);

注意:抽象方法没有方法体(没有 {},直接以分号结尾)。

3. 抽象类的特点

文件Demo01.java

特性 说明
关键字 抽象类和抽象方法必须使用 abstract 关键字修饰
抽象方法所在类 有抽象方法的类必须是抽象类
抽象类中的抽象方法 抽象类中不一定要有抽象方法,但抽象方法必须在抽象类中
实例化 抽象类不能实例化(不能创建对象)
构造方法 抽象类可以有构造方法(供子类通过 super() 调用)
子类选择 ① 重写父类所有的抽象方法;② 子类也是抽象类,直接继承父类的抽象方法
继承关系 抽象父类和具体子类之间是继承关系,子类仍然属于父类类型

二、抽象类代码示例

示例 1:动物体系(Animal → Cat / Dog)

抽象父类 Animal

文件Animal.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

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

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

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

package course;

// 有抽象方法的类必须是抽象类
public abstract class Emp {
    /**
     * 抽象方法——没有方法体
     */
    public abstract void work();
}
  • 只定义了一个抽象方法 work()
  • 类必须使用 abstract 修饰

子类 javaEmp

文件javaEmp.java

package course;

public class javaEmp extends Emp {
    @Override
    public void work() {
        System.out.println("Java开发工程师在开发Java项目");
    }
}
  • 重写父类的 work() 抽象方法,给出具体的实现
  • 不同子类可以提供不同的实现(例如还可以有 前端开发工程师后端测试工程师 等)

示例 3:服务层体系(BaseService → UserService)

抽象父类 BaseService

文件BaseService.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

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:abstractfinal 能否同时修饰一个类或方法?

不能。abstract 表示需要被继承/重写,final 表示不能被继承/重写,二者语义冲突。


五、拓展阅读

  • Java 抽象类(Oracle 官方文档)
  • 抽象类 vs 接口(Interface)的区别(将在后续课程中讲解)
  • 模板方法设计模式(Template Method Pattern)—— 抽象类的经典应用场景