- 什么是抽象方法?
- 抽象方法的语法和规则
- 为什么需要抽象方法?(核心作用)
- 抽象类 和抽象方法的关系
- 代码示例
- 关键要点总结
什么是抽象方法?
抽象方法就是一个没有具体实现(没有方法体)的方法。

它只定义了方法的签名(方法名、参数列表、返回类型),但告诉所有继承它的子类:“你必须实现我,但我不知道你具体要怎么做”。
你可以把它想象成一个“合同”或“模板”中的条款,规定了必须要有某个功能,但没有规定这个功能的具体实现细节。
抽象方法的语法和规则
抽象方法的定义非常简单,只需要在普通方法声明前加上 abstract 关键字,并且去掉方法体的大括号 ,直接用分号
语法:

[访问修饰符] abstract 返回类型 方法名(参数列表);
示例:
public abstract void draw(); // 没有参数,没有返回值 public abstract double calculateArea(); // 返回一个 double 值 protected abstract String getName(int id); // 带有参数
重要规则:
- 没有方法体:这是最核心的特征,绝对不能像这样写
public abstract void draw() { ... },这是错误的。 - 必须存在于抽象类中:一个非抽象的普通类不能包含抽象方法,如果一个类中包含了至少一个抽象方法,那么这个类必须被声明为
abstract。 - 不能是
private或final的:- 不能是
private:因为抽象方法必须被子类实现,而private方法无法被子类继承和访问。 - 不能是
final:因为final方法不能被重写,而抽象方法的本质就是要求子类去重写(实现)它。
- 不能是
为什么需要抽象方法?(核心作用)
抽象方法是实现多态 和 模板方法设计模式 的基石,它的主要作用有:
a) 强制子类提供具体实现
这是最直接的作用,当你定义一个“通用”概念时,形状”(Shape),你知道所有形状都有“绘制”(draw)这个行为,但你无法在“形状”这个层面上写出绘制代码,因为圆形、方形的绘制方式完全不同。

通过在 Shape 类中将 draw() 声明为抽象方法,你就强制了任何继承自 Shape 的具体子类(如 Circle, Square)必须提供它们自己的 draw() 实现,否则,子类将无法通过编译。
b) 实现多态
这使得我们可以用一种统一的方式来处理不同的对象。
假设我们有以下类结构:
Shape (抽象类) -> Circle, Square (具体子类)
我们可以在代码中这样写:
Shape myShape1 = new Circle(); Shape myShape2 = new Square(); myShape1.draw(); // 调用的是 Circle 的 draw() 方法 myShape2.draw(); // 调用的是 Square 的 draw() 方法
尽管 myShape1 和 myShape2 的声明类型都是 Shape,但它们在运行时会根据实际的对象类型(Circle 或 Square)来调用正确的 draw() 方法,这就是多态,而抽象方法是实现这种“约定式”多态的关键。
c) 定义模板/契约
抽象方法和抽象类共同构成了一个“模板”,抽象类定义了所有子类共有的属性和部分方法(非抽象方法),而抽象方法则定义了子类必须实现的“契约”,这保证了所有子类都具有一组一致的行为接口,使得整个系统更加规范和易于维护。
抽象类 和抽象方法的关系
这两者密不可分:
- 包含关系:如果一个类中包含了至少一个抽象方法,那么这个类必须被声明为
abstract类。 - 独立存在:一个抽象类不一定必须包含抽象方法,它也可以没有抽象方法,但这样声明它为
abstract通常是为了防止它被直接实例化,只允许创建其子类的对象。
抽象类的特点:
- 不能被实例化:你不能像
new Shape()这样创建抽象类的对象,它只能作为父类被继承。 - 可以包含构造方法:虽然不能被实例化,但抽象类可以有构造方法,这个构造方法会在创建子类对象时被调用(通过
super())。 - 可以包含成员变量、普通方法、静态方法:除了抽象方法,抽象类和普通类没有太大区别,可以包含任何成员。
- 可以包含抽象方法:这是它最核心的特征。
代码示例
下面是一个经典的“形状”例子,可以很好地展示抽象方法的使用。
步骤 1: 定义抽象父类 Shape
// Shape.java
public abstract class Shape {
// 成员变量
private String color;
// 构造方法
public Shape(String color) {
this.color = color;
}
// 抽象方法:没有方法体,子类必须实现
public abstract double calculateArea();
// 普通方法:有具体实现,子类可以选择重写
public void displayInfo() {
System.out.println("This is a shape with color: " + color);
}
// Getter
public String getColor() {
return color;
}
}
步骤 2: 创建具体子类 Circle 和 Square
// Circle.java
public class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
// 调用父类的构造方法
super(color);
this.radius = radius;
}
// 必须实现父类的抽象方法
@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
// 可以选择重写父类的普通方法
@Override
public void displayInfo() {
System.out.println("This is a Circle with radius: " + radius);
}
}
// Square.java
public class Square extends Shape {
private double side;
public Square(String color, double side) {
super(color);
this.side = side;
}
// 必须实现父类的抽象方法
@Override
public double calculateArea() {
return side * side;
}
}
步骤 3: 在主程序中测试多态
// Main.java
public class Main {
public static void main(String[] args) {
// 创建具体子类的对象
Shape circle = new Circle("Red", 5.0);
Shape square = new Square("Blue", 4.0);
// 使用父类类型的引用来调用方法
// 这体现了多态
System.out.println("--- Circle ---");
circle.displayInfo(); // 调用 Circle 重写的 displayInfo()
System.out.println("Area: " + circle.calculateArea()); // 调用 Circle 的 calculateArea()
System.out.println("\n--- Square ---");
square.displayInfo(); // 调用 Square 重写的 displayInfo()
System.out.println("Area: " + square.calculateArea()); // 调用 Square 的 calculateArea()
}
}
输出结果:
--- Circle ---
This is a Circle with radius: 5.0
Area: 78.53981633974483
--- Square ---
This is a Square with side: 4.0
Area: 16.0
从 main 方法可以看出,我们用 Shape 类型的引用 circle 和 square 来操作对象,但程序在运行时能正确地调用到各自子类中实现的 calculateArea() 和 displayInfo() 方法,这就是抽象方法和多态的威力。
关键要点总结
| 特性 | 描述 |
|---|---|
| 定义 | 只有方法签名(声明),没有方法体 的方法。 |
| 关键字 | 使用 abstract 修饰。 |
| 所在类 | 必须存在于 abstract 类中。 |
| 实例化 | 抽象方法本身不能被调用,它所在的抽象类也不能被实例化。 |
| 子类要求 | 任何继承抽象类的具体子类必须实现(重写)其所有的抽象方法。 |
| 访问修饰符 | 不能是 private 或 final。 |
| 核心目的 | 强制子类实现特定功能。 为多态提供基础,实现“统一接口,多种实现”。 定义模板,规范子类的行为。 |
希望这个详细的解释能帮助你完全理解 Java 中的 abstract 方法!
