CodeGym /课程 /JAVA 25 SELF /抽象类与抽象方法:语法与示例

抽象类与抽象方法:语法与示例

JAVA 25 SELF
第 19 级, 课程 1
可用

1. 抽象类的语法

先来看看什么是 Java 中的抽象类,以及为什么需要它。想象你有一套 LEGO 积木:你有一些通用零件(例如“轮子”、“积木块”),也有针对具体模型的特殊零件。抽象类就像是一份关于如何处理这些零件的通用说明,而不是具体模型的拼装步骤:积木块通过卡扣连接,轮子装在轴上,零件可以一层层加上去。抽象类描述的正是这些通用规则和必要步骤,但不写出具体模型的拼装流程。具体模型就是子类:它们拿到通用说明,再补上缺失的步骤。

在 Java 中,抽象类是不能被直接实例化的类(不能写 new AbstractClass()),但可以从它继承,并在子类中实现那些“尚未完成”的方法。

在以下场景中应考虑使用抽象类:

  • 一组对象具有共同的行为或状态,但部分逻辑不同。
  • 你希望实现一部分“默认”功能,而把另一部分留给子类实现。
  • 你希望禁止直接创建该类的对象(例如,“动物”本身并不会单独出现,而“猫”则会)。

如何声明抽象类

很简单:在 class 前加上关键字 abstract。

public abstract class Animal {
    // 字段(例如动物的名字)
    protected String name;

    // 构造函数
    public Animal(String name) {
        this.name = name;
    }

    // 抽象方法——只有声明,没有实现!
    public abstract void makeSound();

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

要点:

  • 抽象类既可以包含已实现的方法,也可以包含抽象方法。
  • 抽象类可以包含字段、构造函数,甚至 static 方法。
  • 不能直接创建抽象类对象:
  • Animal a = new Animal("某人"); // 错误!

如何声明抽象方法

抽象方法没有方法体,也就是没有花括号和内部代码。用关键字 abstract 声明,并且必须以分号 ; 结束。

public abstract void makeSound();
  • 抽象方法只能在抽象类中声明。
  • 继承抽象类的类必须实现所有抽象方法,否则它本身也必须是 abstract。

2. 继承抽象类:如何工作

来看一个具体例子。假设有抽象类 Animal,其中包含抽象方法 makeSound()。现在创建一个子类 Dog 来实现该方法:

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

    @Override
    public void makeSound() {
        System.out.println(name + " 在叫:汪汪!");
    }
}

再来一个子类:

public class Cat extends Animal {
    public Cat(String name) {
        super(name);
    }

    @Override
    public void makeSound() {
        System.out.println(name + " 在叫:喵!");
    }
}

现在我们可以在程序里这样使用它们:

public class Main {
    public static void main(String[] args) {
        Animal dog = new Dog("Buddy");
        Animal cat = new Cat("Kitty");

        dog.makeSound(); // Buddy 在叫:汪汪!
        cat.makeSound(); // Kitty 在叫:喵!

        dog.sleep(); // Buddy 在睡觉:Zzz...
        cat.sleep(); // Kitty 在睡觉:Zzz...
    }
}

请注意:
我们可以声明类型为 Animal 的变量,但只能创建具体(非抽象)子类的对象。

示意图:结构如下


.         Animal (abstract)
            /         \
         Dog         Cat
 (实现 makeSound) (实现 makeSound)

3. 何时使用抽象类,何时使用接口?

这是面试中最常见的问题之一,原因很充分!我们来梳理一下:

  • 抽象类:当对象有共同状态(例如字段)和共同逻辑(带实现的方法),并且你希望提供一个“行为骨架”,留出可扩展的部分时。
  • 接口:当你只想规定一组方法(契约),而不提供实现与状态时。自 Java 8 起,接口可以有 default/static 方法,但总体而言,接口强调“对象应该会做什么”,而不是“如何去做”。

生活中的例子:
“鸟”是抽象类:所有鸟都有喙、翅膀,并且都会飞(但飞法不同)。
“会飞的”是接口:不仅鸟会飞,飞机、超级英雄也会!它们飞行的方式各不相同,但关键是具备“会飞”的能力。

4. 实用示例

示例 1:带部分实现的抽象类

假设你在做一款游戏,里面有不同的交通工具。它们都会移动,但方式不同。不过它们都有速度、名称以及标准的停止方式。

public abstract class Transport {
    protected String name;
    protected int speed;

    public Transport(String name, int speed) {
        this.name = name;
        this.speed = speed;
    }

    // 抽象方法——由子类实现
    public abstract void move();

    // 已实现的方法
    public void stop() {
        System.out.println(name + " 停下来了。");
    }
}

public class Car extends Transport {
    public Car(String name, int speed) {
        super(name, speed);
    }

    @Override
    public void move() {
        System.out.println(name + " 在公路上以 " + speed + " km/h 行驶。");
    }
}

public class Bicycle extends Transport {
    public Bicycle(String name, int speed) {
        super(name, speed);
    }

    @Override
    public void move() {
        System.out.println(name + " 以 " + speed + " km/h 踩踏板。");
    }
}

使用方式:

Transport car = new Car("Toyota", 120);
Transport bike = new Bicycle("Stealth", 25);

car.move(); // Toyota 在公路上以 120 km/h 行驶。
bike.move(); // Stealth 以 25 km/h 踩踏板。

car.stop(); // Toyota 停下来了。
bike.stop(); // Stealth 停下来了。

示例 2:带参数的抽象方法

public abstract class Shape {
    public abstract double area();
}

public class Circle extends Shape {
    private double radius;
    public Circle(double radius) {
        this.radius = radius;
    }
    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
}

public class Rectangle extends Shape {
    private double width, height;
    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }
    @Override
    public double area() {
        return width * height;
    }
}

使用方式:

Shape c = new Circle(3);
Shape r = new Rectangle(4, 5);

System.out.println("圆的面积:" + c.area());
System.out.println("矩形的面积:" + r.area());

5. 抽象类的特性与细节

  • 抽象类可以使用任意访问修饰符:public、protected、private(例如用于字段)。
  • 可以声明没有任何抽象方法的抽象类。如果你只是想禁止实例化基类,这会很有用。
  • 如果类继承了抽象类却没有实现所有抽象方法,它也必须声明为 abstract。
  • 抽象类可以有构造函数。创建子类对象时会调用它们(通过 super(...))。
  • 抽象方法不能是 private(否则无法在子类中实现)。
  • 抽象类可以包含 static 方法和字段。
  • 抽象类可以实现接口,但不必实现其方法——可以由子类来完成。

表格:抽象类与接口的对比

抽象类 接口
关键字
abstract class
interface
是否可包含字段 是(任意) 自 Java 8 起——仅 static/final
带实现的方法 是 自 Java 8 起——default/static
抽象方法 是 是
多重继承 否 是(可以实现多个接口)
构造函数 是 否
能否创建对象 否 否

6. 使用抽象类和抽象方法的常见错误

错误 №1:尝试创建抽象类的实例。
如果你写出 new Animal("某人"),编译器会立即提醒你抽象类并非为此而生。记住:抽象是“骨架”,不是“活体”。

错误 №2:在子类中遗漏了抽象方法的实现。
如果你的类没有实现基类中的任意一个抽象方法,它本身就必须声明为 abstract,否则会得到编译错误。

错误 №3:在非抽象类中声明抽象方法。
在 Java 中,不能在普通(非抽象)类里声明抽象方法——编译器会立刻报错。

错误 №4:试图把抽象方法声明为 private 或 static。
抽象方法不能是 private(否则无法重写),也不能是 static(因为静态方法不能被重写)。同时也不能是 final,因为 final 禁止重写。

错误 №5:忘记为抽象方法指定访问修饰符。
如果你没有显式指定修饰符,方法将具有包可见性(package-private),这有时并非你的本意。

1
任务
JAVA 25 SELF, 第 19 级, 课程 1
已锁定
加密机:带参数的方法 🔐
加密机:带参数的方法 🔐
1
任务
JAVA 25 SELF, 第 19 级, 课程 1
已锁定
智能家居管理系统 📱
智能家居管理系统 📱
1
任务
JAVA 25 SELF, 第 19 级, 课程 1
已锁定
几何编辑器:图形及其面积 📐
几何编辑器:图形及其面积 📐
1
任务
JAVA 25 SELF, 第 19 级, 课程 1
已锁定
IT公司人事系统 💼
IT公司人事系统 💼
评论 (1)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
悠 级别 1,-,Hong Kong
7 九月 2026
我都怀疑我是不是中间一不小心跳过了接口这节课