抽象类必须用abstract关键字修饰且不能实例化,可含抽象与具体方法,子类须实现全部抽象方法或声明为abstract,与接口区别在于支持字段和构造器。

抽象类必须用 abstract 关键字修饰,且不能被实例化
Java 中定义抽象类的硬性要求是:类声明前必须加 abstract 关键字,否则编译器会报错 error: class X is not abstract and does not override abstract method Y(如果它包含抽象方法)。更重要的是,哪怕类里没有任何抽象方法,只要用了 abstract 修饰,就无法直接 new 实例——这是设计意图,不是语法漏洞。
常见误操作是写完抽象类后顺手加了 new MyAbstractClass(),JVM 立即抛出 java.lang.InstantiationError。这和接口不能实例化一样,属于语言层强制约束。
-
abstract是修饰符,只能放在class前,不能用于字段或局部变量 - 抽象类可以有构造方法,但仅用于子类调用(通过
super()),自身不参与实例创建 - 抽象类可以同时包含
abstract方法和具体实现方法,这点比接口更灵活
abstract 方法不能有方法体,且所在类必须声明为抽象类
只要方法签名后跟分号、不写花括号,就是抽象方法:public abstract void doSomething();。这种写法一旦出现,编译器立刻要求整个类必须用 abstract 修饰,否则直接编译失败。没有例外,哪怕只有一行 abstract 方法也不行。
注意:抽象方法不能是 private、static 或 final——因为它们违背“强制子类重写”的语义。private 方法子类不可见;static 属于类而非实例,无法被多态调用;final 明确禁止重写。
立即学习“Java免费学习笔记(深入)”;
abstract class Animal {
public abstract void makeSound(); // ✅ 正确:无方法体,public + abstract
// private abstract void run(); // ❌ 编译错误
// static abstract void sleep(); // ❌ 编译错误
// final abstract void eat(); // ❌ 编译错误
}
子类继承抽象类必须实现所有抽象方法,或自己也声明为 abstract
非抽象子类继承抽象类时,编译器会逐个检查未实现的抽象方法。漏掉一个,就会报错 error: X is not abstract and does not override abstract method Y in Z。解决方式只有两种:补全所有 abstract 方法的实现,或者把子类也改成 abstract 类(适用于构建中间抽象层)。
实现时要注意访问权限不能比父类抽象方法更严格。比如父类是 protected abstract void foo(),子类实现不能写成 private void foo(),否则编译不通过。
- 子类用
@Override注解不是必须的,但强烈建议加上,便于 IDE 校验和后期维护 - 如果父类抽象方法是
public,子类实现也必须是public(不能降级为protected或package-private) - 抽象类可以继承另一个抽象类,无需实现父类的抽象方法(留给最终非抽象子类处理)
抽象类与接口的关键区别影响设计选择
当纠结该用抽象类还是接口时,核心判断点是:是否需要共享状态(字段)或默认行为(具体方法)。抽象类支持普通字段、构造器、静态代码块、甚至 main 方法;接口在 Java 8+ 虽然能有 default 和 static 方法,但不能有实例字段(只能是 public static final 常量)。
典型场景:如果你需要让多个子类共用一个计数器字段 protected int id;,或提供一段通用初始化逻辑(如日志打印、资源预加载),就必须用抽象类。接口做不到这点。
另一个常被忽略的点是单继承限制:一个类只能 extends 一个抽象类,但可以 implements 多个接口。所以组合使用更常见——抽象类定义骨架,接口定义能力契约。
别为了“看起来更面向对象”而强行抽象。空的抽象类(没抽象方法也没字段)、只有一两个抽象方法却带一堆冗余构造逻辑的类,往往暴露设计过早或职责不清。








