抽象类与接口的核心区别在于设计意图:抽象类体现“is-a”关系,用于代码复用和部分实现;接口体现“can-do”关系,用于定义行为契约和多态。

Java 中区分接口与抽象类,关键不在死记语法条目,而在于抓住“谁在定义什么”这个设计意图。语法是表象,背后的建模逻辑才是判断依据。
看定义关键字和继承方式
这是最直接的识别方式:
- 用 abstract class 声明的是抽象类,子类必须用 extends 继承,且只能继承一个;
- 用 interface 声明的是接口,类必须用 implements 实现,且可以同时实现多个。
比如:class Dog extends Animal 是继承抽象类;class Dog implements Runnable, Serializable 是实现接口。单继承 vs 多实现,是语法层最硬的分水岭。
看能不能存状态和初始化对象
抽象类可以有构造方法、普通成员变量(private/protected)、可变字段;接口不行。
- 抽象类里写
protected String name;或public Animal(String name) { this.name = name; }是合法的; - 接口里声明变量,自动变成
public static final,本质只是常量,不能存实例状态;也没有构造方法,无法参与对象初始化。
所以,如果一段代码里出现了构造器或非 final 的字段,那它一定是抽象类,不是接口。
看方法能不能带具体实现和访问控制
抽象类的方法可以是 private、protected、public,也可以有完整方法体;接口的方法默认 public,且直到 JDK 9 才支持 private 方法——但仅限于内部复用,默认对外仍是公开契约。
- 抽象类中写
private void init() { ... }或protected void log() { ... }没问题; - 接口中所有抽象方法隐式是
public abstract,default 方法也必须是public,static 方法同理;私有方法只用于接口内部,不能被实现类调用。
换句话说:能控制方法可见性、能封装内部逻辑细节的,是抽象类;所有公开方法都面向外部约定的,是接口。
看设计关系是 “是什么” 还是 “能做什么”
这不是语法,却是判断该用哪个的真正依据:
- 如果描述的是同一类事物的共性模板(比如“哺乳动物都有呼吸、心跳、体温调节”),适合用抽象类——体现 is-a 关系;
- 如果描述的是跨类型的能力规范(比如“能排序”“能比较”“能序列化”),适合用接口——体现 can-do 或 has-a 关系。
例如:java.util.List 是接口,因为 ArrayList、LinkedList 虽无继承关系,但都需要提供“按索引访问”“增删元素”等能力;而 java.time.temporal.Temporal 是抽象类的思路(实际是接口,但设计上更接近契约),反例是 java.io.InputStream 抽象类,它封装了 read() 等通用读取逻辑,子类只需关注数据源差异。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











