抽象方法只能定义在abstract类或接口中,普通类中声明会编译报错;接口中默认public abstract,不可private/protected或含方法体;abstract类可含具体成员,接口不可(除default/static);子类继承或实现时必须严格重写所有抽象方法,签名一致、异常不扩大、返回值协变;static/private/final与abstract互斥;interface中带方法体的是default/static方法,非抽象方法。

抽象方法必须定义在 abstract 类或接口里
Java 不允许在普通类中声明抽象方法,否则编译直接报错 abstract methods cannot be in a non-abstract class。这意味着只要类里有一个 abstract 方法,这个类就必须用 abstract 修饰。
接口(interface)从 Java 8 开始也支持抽象方法,且默认就是 public abstract,哪怕你不写这两个修饰符。但注意:接口中的抽象方法不能是 private 或 protected,也不能有方法体(哪怕空大括号也不行)。
-
abstract类可以包含具体方法、字段、构造器;接口不行(Java 8+ 允许default和static方法,但它们不是抽象的) - 一个类继承
abstract类,必须实现所有未实现的抽象方法,否则自己也得声明为abstract - 一个类实现接口,必须实现接口中所有抽象方法(除非该类也是
abstract)
子类实现抽象方法时签名必须严格一致
重写抽象方法不是“随便写个同名方法就行”,JVM 会校验方法签名(名称 + 参数类型 + 泛型擦除后类型),返回值类型需协变(比如父类声明返回 Number,子类可返回 Integer),但不能随意改成无关类型。
常见翻车点:
立即学习“Java免费学习笔记(深入)”;
- 父类抽象方法是
void doWork(String s),子类写成void doWork(Object s)→ 编译失败,这不是重写,是重载 - 接口中方法是
default void log(),子类想“覆盖”它,但没加@Override→ 可能误以为生效了,实际只是新增了一个同名方法 - 抽象方法抛出
IOException,子类实现时抛出Exception→ 编译失败,子类不能扩大异常范围
抽象方法不能是 static、private、final
这三条是硬性限制,违反任一都会触发编译错误:
-
static abstract void f()→ 错误:illegal combination of modifiers: abstract and static -
private abstract void f()→ 错误:illegal combination of modifiers: abstract and private -
final abstract void f()→ 错误:illegal combination of modifiers: abstract and final
原因很直接:抽象方法的意义是“强制子类提供具体实现”,而 static 属于类本身、private 不可被继承、final 禁止重写——三者和抽象方法的设计目标完全冲突。
接口中 default 方法不是抽象方法,别混淆
这是新手最容易误解的一点:看到接口里有方法体,就以为“它不算抽象方法”。但关键看有没有 abstract 修饰符(显式或隐式)。
以下都是抽象方法(即使没写 abstract):
interface Service {
void start(); // 隐式 public abstract
String getName(); // 同上
}而这些不是抽象方法:
interface Service {
default void stop() { System.out.println("stopped"); }
static void utils() { /* ... */ }
}它们的存在不改变接口的“抽象性”,但也不会被子类强制实现。如果你在 IDE 里 Ctrl+Click 进去某个接口方法,发现它有方法体,那它大概率是 default 方法,不是抽象方法。
真正容易被忽略的是:当一个类同时继承抽象类又实现接口,且两者有签名相同的方法时,抽象类的抽象方法优先级更高,子类必须实现它——哪怕接口里提供了 default 实现,也不能跳过。









