abstract(抽象)是 Java 中一个非常重要的关键字,它用于定义抽象方法和抽象类,是实现多态和设计模式(如模板方法模式)的核心机制之一。

什么是抽象方法?
抽象方法是一种没有具体实现(没有方法体)的方法,它只声明了方法的签名(方法名、参数列表和返回类型),但没有 括号中的代码。
语法格式:
[访问修饰符] abstract 返回类型 方法名(参数列表);
关键点:
- 必须以
abstract关键字开头。 - 没有方法体,即分号 而不是 。
- 必须存在于抽象类中(或接口中,但接口中的方法默认是抽象的,从 Java 8 开始可以有默认实现)。
示例:

public abstract class Animal {
// 这是一个抽象方法
public abstract void makeSound(); // 只有声明,没有实现
// 这是一个普通方法,有具体实现
public void eat() {
System.out.println("This animal is eating.");
}
}
抽象方法的作用和意义
抽象方法的核心作用是定义一个“契约”或“规范”,它告诉所有继承这个抽象类的子类:“你们都必须实现 makeSound() 这个方法,但我不管你们具体怎么实现(是“汪汪叫”还是“喵喵叫”)”。
这带来了几个关键好处:
- 强制子类实现:如果一个非抽象类继承了一个抽象类,那么它必须为父类中的所有抽象方法提供具体的实现,否则,这个子类也必须被声明为
abstract。 - 实现多态:通过抽象方法,我们可以定义一个通用的接口(父类引用),然后让不同的子类用自己的方式来实现这个接口,这使得代码更加灵活和可扩展。
- 建立模板:抽象类可以看作是一个“模板”,它定义了所有子类共有的属性和行为(普通方法),同时规定了一些子类必须具备的、但具体实现不同的行为(抽象方法)。
抽象类
抽象类是使用 abstract 关键字修饰的类,它不仅可以包含抽象方法,也可以包含普通方法、构造方法、字段和静态方法。
关键规则:

- 不能被实例化:你不能直接创建一个抽象类的对象。
new Animal();是错误的,这符合逻辑,因为一个抽象类代表的是一个不完整的概念(动物”不是一个具体的动物),你不能直接创建一个不完整的对象。 - 子类的责任:
- 如果一个非抽象类继承了一个抽象类,它必须实现(重写)父类中的所有抽象方法。
- 如果一个子类不想或不能实现所有抽象方法,那么它自己也必须被声明为
abstract。
示例:
定义抽象类 Animal
public abstract class Animal {
// 抽象方法,子类必须实现
public abstract void makeSound();
// 普通方法,子类可以直接继承使用
public void sleep() {
System.out.println("This animal is sleeping.");
}
}
创建具体的子类 Dog 并实现抽象方法
public class Dog extends Animal {
// 必须实现父类的抽象方法
@Override
public void makeSound() {
System.out.println("Woof! Woof!");
}
}
创建具体的子类 Cat 并实现抽象方法
public class Cat extends Animal {
// 必须实现父类的抽象方法
@Override
public void makeSound() {
System.out.println("Meow!");
}
}
使用多态
public class Main {
public static void main(String[] args) {
// Animal animal = new Animal(); // 错误!不能实例化抽象类
// 使用父类引用指向子类对象(多态)
Animal myDog = new Dog();
Animal myCat = new Cat();
myDog.makeSound(); // 输出: Woof! Woof!
myDog.sleep(); // 输出: This animal is sleeping.
myCat.makeSound(); // 输出: Meow!
myCat.sleep(); // 输出: This animal is sleeping.
}
}
抽象类 vs. 接口
这是一个非常经典且重要的问题,在 Java 8 之前,抽象类和接口有明确的区别,Java 8 引入默认方法和静态方法后,它们的界限变得模糊,但核心设计理念仍有不同。
| 特性 | 抽象类 | 接口 |
|---|---|---|
| 方法实现 | 可以包含抽象方法和具体方法(有方法体)。 | 从 Java 8 开始,可以包含默认方法和静态方法(有方法体),抽象方法默认是 public abstract。 |
| 字段 | 可以包含各种类型的字段(public, protected, private, static, final),不一定是 public static final。 |
字段隐式为 public static final(常量)。 |
| 构造方法 | 有构造方法,虽然不能直接实例化,但子类在构造时会调用父类的构造方法。 | 没有构造方法。 |
| 继承 | 单继承,一个类只能继承一个抽象类。 | 多实现,一个类可以实现多个接口。 |
| 设计目的 | "is-a" (是一个) 的关系,表示子类是父类的一种特例,共享代码和状态,它是一个模板,定义了基本行为。 | "can-do" (能做) 的关系,表示一个类具备某种能力(行为),是一种契约或规范,它更像是一个角色。 |
如何选择?
- 当多个类共享代码和状态,并且它们之间是“是一个”的关系时,使用抽象类。
Dog和Cat都是Animal的一种。Animal可以有name字段和sleep()方法。
- 当你想定义一个类的行为契约,并且希望一个类能够实现多个这样的契约时,使用接口。
- 一个
Plane和一个Bird都能fly(),但它们没有共同的“是一个”关系。Flyable接口定义了fly()行为。
- 一个
abstract方法:只有声明,没有实现,用于定义规范。abstract类:可以包含abstract方法和普通方法,但不能被实例化。- 核心作用:强制子类实现特定方法,是实现多态和代码模板化的基础。
- 使用场景:当你希望创建一个基类,为子类提供一些通用的实现,同时又强制子类必须实现某些特定功能时,抽象类是理想的选择。
- 与接口的区别:抽象类强调“是什么”(is-a),共享代码和状态;接口强调“能做什么”(can-do),定义行为契约,支持多实现。
理解抽象方法是掌握 Java 面向对象编程和设计模式的关键一步。
