1. 语法上的区别(最基础的)
抽象类:
- 用
abstract class声明。 - 可以包含抽象方法(没有方法体)和具体方法。
- 可以定义成员变量(可以是任意访问权限)。
- 构造器:有构造器,但不能直接
new。
- 用
接口(JDK 8+):
- 用
interface声明。 - 可以包含:抽象方法、默认方法(
default修饰,有方法体)、静态方法(static修饰,有方法体)。 - 成员变量默认是
public static final的(常量)。 - 没有构造器。
- 用
2. 本质上的区别(我自己的“顿悟”)
抽象类: 表示的是一种 “is-a” 关系,是一种模板设计。
- 例子:
Animal是一个抽象类,Dog和Cat继承它。Dog是一个Animal。抽象类Animal可以定义所有动物共有的属性和行为(如name,eat(),sleep()),有些行为是具体的(sleep()),有些是抽象的(makeSound(),由子类实现)。 - 核心思想: 代码复用。子类继承父类的功能,并实现或覆盖特定部分。
- 例子:
接口: 表示的是一种 “has-a” 或 “can-do” 关系,是一种契约/规范。
- 例子:
Flyable(会飞的)、Swimmable(会游泳的)是接口。一架Airplane(飞机)不是一种Bird(鸟),但它们都具有飞行的能力,所以都可以实现Flyable接口。 - 核心思想: 定义行为规范,实现多态。一个类可以实现多个接口,从而具备多种能力。
- 例子:
3. 实战中如何选择?
- 当你关注事物本身的本质,需要强大的代码复用时,用抽象类。 比如:各种业务单据(订单、入库单、出库单)可能有共同的流程处理逻辑。
- 当你关注事物的某个能力或行为,希望不相关的类也能具备此能力时,用接口。 比如:一个
Printer类需要实现Printable接口,一个Logger类也需要实现Printable接口来打印自己的状态,但它们本身没有继承关系。
一句话总结:
“像”什么就用抽象类继承,“有”什么能力就用接口实现。 在复杂的系统中,通常是抽象类定义核心骨架,接口定义扩展能力。