Skip to content

抽象类:定义「是什么」

有这样一种情况:你想定义一个类来表示「图形」,但你无法确定「图形」的具体行为——圆有面积计算方法,三角形也有,但它们的算法完全不同。

你能写出 Shape 类的 getArea() 方法吗?写不出来,但又想表达「所有图形都应该有面积」这个概念。

这时抽象类就派上用场了。

抽象类是什么

抽象类(Abstract Class)是不能直接实例化的类。它的主要作用是定义契约,让子类去实现具体行为。

java
public abstract class Shape {
    // 抽象方法:没有实现,强制子类重写
    public abstract double getArea();

    // 普通方法:有默认实现,子类可选重写
    public void print() {
        System.out.println("面积:" + getArea());
    }
}

定义抽象类

java
public abstract class Animal {
    protected String name;

    // 抽象方法:没有方法体
    public abstract void eat();
    public abstract void sound();

    // 普通方法:有实现
    public void sleep() {
        System.out.println(name + "在睡觉");
    }
}

abstract 关键字告诉编译器:「这个类不完整,不能直接 new」。

子类实现

继承抽象类的子类必须实现所有抽象方法(除非它自己也是抽象类):

java
public class Dog extends Animal {
    public Dog(String name) {
        this.name = name;
    }

    @Override
    public void eat() {
        System.out.println(name + "在吃狗粮");
    }

    @Override
    public void sound() {
        System.out.println(name + "汪汪叫");
    }
}

使用:

java
Animal animal = new Dog("旺财");
animal.eat();    // 旺财在吃狗粮
animal.sleep();  // 旺财在睡觉(继承自父类)

抽象类的特点

1. 不能实例化

java
// ❌ 错误:抽象类不能 new
Animal animal = new Animal();

// ✅ 正确:创建子类对象
Animal animal = new Dog("旺财");

2. 可以有构造方法

抽象类的构造方法不是为了给自己用,而是供子类初始化父类状态:

java
public abstract class Animal {
    protected String name;

    // 抽象类可以有构造方法
    public Animal(String name) {
        this.name = name;
    }
}

public class Dog extends Animal {
    public Dog(String name) {
        super(name);  // 调用父类构造
    }
}

3. 可以有普通方法

普通方法提供默认实现,子类可以直接使用,也可以重写:

java
public abstract class Animal {
    protected String name;

    // 有默认实现
    public void breathe() {
        System.out.println(name + "在呼吸");
    }

    // 没有默认实现
    public abstract void eat();
}

4. 单继承限制

抽象类仍然受 Java 单继承限制:

java
// ✅ 正确:多层继承
abstract class A { }
abstract class B extends A { }  // B 继承 A
class C extends B { }            // C 继承 B

// ❌ 错误:不能多继承
// abstract class C extends A, B { }

模板方法模式

抽象类的经典应用是模板方法模式:父类定义算法骨架,具体步骤由子类实现。

java
public abstract class DataProcessor {
    // 模板方法:final 防止被重写
    public final void process() {
        String raw = readData();
        String result = processData(raw);
        saveData(result);
    }

    // 抽象方法:子类必须实现
    protected abstract String readData();
    protected abstract String processData(String data);

    // 普通方法:有默认实现
    protected void saveData(String data) {
        System.out.println("保存结果:" + data);
    }
}

public class FileProcessor extends DataProcessor {
    @Override
    protected String readData() {
        return "从文件读取的数据";
    }

    @Override
    protected String processData(String data) {
        return data.toUpperCase();
    }
}

调用 new FileProcessor().process() 会依次执行:读取 → 处理 → 保存。算法骨架不变,具体步骤由子类决定。

抽象类 vs 接口

对比项抽象类接口
关键字abstract classinterface
继承单继承多实现
构造方法可以有不能有
方法抽象 + 普通都可以JDK 7 前只能是抽象方法
字段无限制只能是常量
访问修饰符任意默认 public
静态方法可以有JDK 8+ 可以有
用途「是什么」(is-a)「能做什么」(can-do)

选型决策树

需要继承多个?
  是 → 用接口
  否 ↓
类之间有明确的"是"关系?
  是 → 用抽象类
  否 ↓
需要共享代码(普通方法)?
  是 → 用抽象类
  否 → 用接口

实际应用:层级结构的抽象

java
// 抽象父类:定义通用属性和通用方法
public abstract class Employee {
    protected String name;
    protected double baseSalary;

    public Employee(String name, double baseSalary) {
        this.name = name;
        this.baseSalary = baseSalary;
    }

    // 抽象方法:子类必须实现
    public abstract double calculateSalary();

    // 普通方法:子类共用
    public void printInfo() {
        System.out.println("姓名:" + name);
        System.out.println("工资:" + calculateSalary());
    }
}

// 正式员工
public class FullTimeEmployee extends Employee {
    private double bonus;

    public FullTimeEmployee(String name, double baseSalary, double bonus) {
        super(name, baseSalary);
        this.bonus = bonus;
    }

    @Override
    public double calculateSalary() {
        return baseSalary + bonus;
    }
}

// 合同工
public class PartTimeEmployee extends Employee {
    private int hours;
    private double hourlyRate;

    public PartTimeEmployee(String name, double baseSalary, int hours, double hourlyRate) {
        super(name, baseSalary);
        this.hours = hours;
        this.hourlyRate = hourlyRate;
    }

    @Override
    public double calculateSalary() {
        return baseSalary + hours * hourlyRate;
    }
}

总结

抽象类 = 不完整的类
抽象方法 = 必须由子类实现的方法
abstract = 「我定义规矩,子类负责实现」

抽象类是「是什么」的抽象——AnimalShapeEmployee——它们代表一类事物的共性,但每个具体事物又有自己的行为。抽象类为这类事物提供了共同的骨架,让代码复用和扩展成为可能。

基于 VitePress 构建