抽象类不能被实例化但可声明引用变量,是设计上拒绝实例化的契约载体;必须通过子类继承并实现抽象方法才能使用,支持构造方法、普通方法和成员变量,强调is-a关系。

抽象类不能 new,但能声明引用变量
抽象类不是“半成品类”,而是设计上就拒绝被实例化的契约载体。你写 new Animal() 会直接编译报错,但写 Animal dog = new Dog(); 完全合法——这是多态的起点,也是最容易混淆的第一步。
- 抽象类可以有构造方法(用于子类初始化时调用),但它只在子类
super()时执行,从不独立运行 - 抽象类的引用变量可以指向任何非抽象子类对象,这是实现“统一操作不同行为”的基础
- 常见错误:试图在测试类里写
Animal a = new Animal();→ 编译器立刻报Cannot instantiate the type Animal
abstract 方法必须被子类重写,除非子类也声明为 abstract
抽象方法不是“可选实现”,是强制接口。它像一张欠条:父类写了“你要实现 eat()”,子类要么还(@Override),要么把这张欠条转给下家(自己也变成 abstract 类)。
- 子类如果漏掉任一 abstract 方法,编译器报错:
The type XXX must implement the inherited abstract method YYY - 子类若选择不实现,必须加
abstract关键字修饰自身,否则无法通过编译 - 抽象方法不能用
private、static、final修饰——这三者和“必须被重写”根本冲突 - 示例:若
Animal有abstract void breathe();,Dog类没重写又没声明为 abstract,代码直接红波浪线
抽象类里可以没有 abstract 方法,但有 abstract 方法就必须是抽象类
有没有 abstract 方法,和是不是抽象类,是单向因果关系:有 abstract 方法 → 必须是 abstract 类;但 abstract 类可以全是具体方法——这种写法其实很常见,目的就是“禁止实例化”,比如封装通用工具逻辑又不想被误 new。
- 典型场景:定义一个基类
BaseService,含公共日志、事务模板方法,但不希望业务方直接 new 它,就加abstract修饰,哪怕一个 abstract 方法都没有 - 反例:删掉
abstract却留着abstract void run();→ 编译报错:Abstract method in non-abstract class - 抽象类中的普通方法、静态方法、构造器、成员变量,全部照常使用,和普通类无异
抽象类 vs 接口?别急着选,先看你要约束的是“是什么”还是“能做什么”
抽象类强调 is-a 关系(Dog 是一种 Animal),接口强调 can-do 关系(Dog 能 Swim)。Java 不支持多继承,但一个类可以实现多个接口——这个限制决定了你怎么组织顶层结构。
- 如果你需要共享状态(如
protected String id;)、构造逻辑、或非 public 方法,只能靠抽象类 - 如果你要让不相关的类(比如
Dog和Boat)都具备同一能力(move()),接口更合适 - Java 8+ 接口可以有 default/static 方法,但依然不能有实例字段或构造器——这点始终是硬边界
@Override 就编译失败,这不是限制,是提前暴露设计断裂点。










