Skip to content

抽象类

概述

抽象类(Abstract Class)是用 abstract 修饰的类,用于表示不能直接实例化的「抽象概念」或「模板」。抽象类可以包含抽象方法(只有声明、没有方法体的方法),也可以包含普通方法、成员变量和构造方法。子类必须实现(重写)父类中的所有抽象方法才能被实例化,否则子类也必须声明为抽象类。抽象类常用于定义一类对象的共同行为骨架,把「必须由子类实现」的部分声明为抽象方法,把「可复用」的部分写成普通方法,从而在 继承多态 中充当稳定的基类。

通俗理解:抽象类像是「半成品模板」——规定好了部分能力(普通方法)和必须由子类补全的「缺口」(抽象方法),本身不能直接 new,只能通过具体子类来用。

前置建议

已掌握 继承多态,理解方法重写和「父类引用指向子类对象」。


为什么需要抽象类

  • 强制子类实现关键行为:把「必须由子类决定」的方法声明为抽象方法,编译器会检查子类是否全部实现,避免漏写。
  • 复用公共逻辑:抽象类中的普通方法、成员变量可被所有子类共享,减少重复代码。
  • 表达「是一种」的层次:抽象类表示「一类事物的抽象」,子类表示具体种类(如 AnimalDogCat),便于面向抽象编程。
  • 与接口的区别:抽象类可以有构造方法、实例字段和已实现的方法,适合作为「带状态的模板」;接口侧重「能力契约」,见 接口

基本语法

声明抽象类

class 前加 abstract

java
public abstract class Animal {
    protected String name;

    public Animal(String name) {
        this.name = name;
    }

    // 抽象方法:无方法体,以分号结束;子类必须实现
    public abstract void speak();

    // 普通方法:子类可直接继承使用或重写
    public void sleep() {
        System.out.println(name + " is sleeping.");
    }
}
  • 抽象类不能 newnew Animal("x") 会编译错误。
  • 抽象方法:用 abstract 修饰,没有方法体(没有 { }),以分号结尾;子类必须提供实现。

子类实现抽象方法

子类必须实现父类中所有抽象方法,否则子类也必须声明为 abstract

java
public class Dog extends Animal {
    public Dog(String name) {
        super(name);   // 调用抽象类的构造方法
    }

    @Override
    public void speak() {
        System.out.println(name + " barks: Wang!");
    }
}

// 此时 Dog 是具体类,可以实例化
Animal a = new Dog("Lucky");
a.speak();   // 多态:Lucky barks: Wang!
a.sleep();   // 使用抽象类中已实现的 sleep()

注意

抽象类可以有构造方法。虽然抽象类本身不能实例化,但子类构造方法中会通过 super(...) 调用父类构造方法,用于初始化抽象类中定义的成员变量。


抽象类与普通类的区别

特性普通类抽象类
abstract必须有
实例化可以 new不能直接 new
抽象方法不能有可以有(0 个或多个)
构造方法/字段可以有可以有
子类可选继承若继承则须实现抽象方法

使用示例

示例 1:抽象类作为模板(抽象方法 + 普通方法)

抽象类定义「模板方法」:一部分步骤已实现,关键步骤留给子类实现。

java
public abstract class DataParser {
    // 抽象方法:子类必须实现「如何读取原始数据」
    protected abstract String readRaw();

    // 抽象方法:子类必须实现「如何解析」
    protected abstract Object parse(String raw);

    // 普通方法:模板流程,子类可直接使用
    public final Object parseFromSource() {
        String raw = readRaw();
        return parse(raw);
    }
}

public class JsonParser extends DataParser {
    @Override
    protected String readRaw() {
        return "{\"name\":\"Java\"}";   // 示例:实际可从文件/网络读
    }

    @Override
    protected Object parse(String raw) {
        // 简化示例:实际可用 JSON 库解析
        return raw;
    }
}

DataParser p = new JsonParser();
Object result = p.parseFromSource();   // 多态:调用子类实现的 readRaw/parse

示例 2:抽象类中的构造方法与字段

抽象类可以拥有构造方法、成员变量和已实现方法,子类通过 super() 初始化并复用。

java
public abstract class Shape {
    private final String color;

    public Shape(String color) {
        this.color = color;
    }

    public String getColor() {
        return color;
    }

    public abstract double area();       // 面积由子类实现
    public abstract double perimeter(); // 周长由子类实现

    // 已实现方法:所有子类共用
    public void printInfo() {
        System.out.println("Color: " + color + ", Area: " + area() + ", Perimeter: " + perimeter());
    }
}

public class Rectangle extends Shape {
    private final double width, height;

    public Rectangle(String color, double width, double height) {
        super(color);   // 必须调用父类构造方法
        this.width = width;
        this.height = height;
    }

    @Override
    public double area() {
        return width * height;
    }

    @Override
    public double perimeter() {
        return 2 * (width + height);
    }
}

Shape s = new Rectangle("red", 3, 4);
s.printInfo();   // Color: red, Area: 12.0, Perimeter: 14.0

示例 3:抽象类与多态结合

用抽象类类型统一持有不同子类对象,体现多态。

java
public abstract class Animal {
    protected String name;
    public Animal(String name) { this.name = name; }
    public abstract void speak();
}

public class Dog extends Animal {
    public Dog(String name) { super(name); }
    @Override
    public void speak() { System.out.println(name + " barks."); }
}

public class Cat extends Animal {
    public Cat(String name) { super(name); }
    @Override
    public void speak() { System.out.println(name + " meows."); }
}

Animal[] animals = { new Dog("Lucky"), new Cat("Mimi") };
for (Animal a : animals) {
    a.speak();   // 多态:各自执行 Dog/Cat 的 speak
}

抽象类的常见用法

  • 定义模板:抽象类中写好流程(普通方法),关键步骤用抽象方法交给子类实现。
  • 作为多态基类:变量/参数类型声明为抽象类,实际传入各种具体子类,统一处理。
  • 部分实现:既有已实现方法(复用),又有抽象方法(强制子类实现),介于「完全实现」的普通类和「只定义契约」的接口之间。

注意事项

  • 抽象类不能实例化new AbstractClass() 会编译报错;只能通过具体子类实例化,再赋给抽象类引用(多态)。
  • 抽象方法不能有方法体:抽象方法以分号结束,不能写 { };实现必须在子类中完成。
  • 子类必须实现全部抽象方法:否则子类也必须声明为 abstract
  • 抽象类可以有构造方法:供子类通过 super(...) 调用,用于初始化抽象类中的字段。
  • 抽象方法不能是 private、static 或 final:抽象方法需要子类重写,因此不能是 private;不能是 static(静态方法属于类,不参与重写);不能是 final(final 禁止重写)。

提示

若一个类中有抽象方法,该类必须声明为抽象类;但抽象类可以没有抽象方法(仅用 abstract class 表示「不允许实例化」)。

注意

抽象类与 接口 都能作为多态的类型;选择抽象类通常是因为需要共同状态(字段)或部分已实现逻辑,而接口更侧重「能力契约」、支持多实现。


相关链接

基于 VitePress 构建