臭名昭著aTrust隔离计划1.臭名昭著aTrust隔离计划2.VPN原理与aTrust隔离网络实践3.docker-easyconnect到底做了什么4.TUN(tunnel-隧道-虚拟网卡)模式
个人项目
personal(个人展示)GitHub Actions 自动部署个人展示项目
基于Quartz搭建的个人博客1.Quartz个人博客使用教程2.使用 rsync 增量部署 Quartz 博客3.使用 GitHub Actions 自动部署 Quartz 博客5.域名绑定6.CDN加速7.Google 搜索收录排查:为什么关键词搜得到别人,却搜不到我的网站?Obsidian、双向链接与知识图谱
架构设计
分布式分布式事务RPC原理
旅行
行程攻略青岛三日游行程攻略
前端
NginxNginx配置与反向代理入门
Nodenpm与npx的区别
数据库
mysql01.MySQL基础语法与约束02.MySQL数据库类型03.MySQL多表查询04.MySQL 索引05.MySQL 事务06.MySQL 隔离级别07.MySQL MVCC08.MySQL 锁09.EXPLAIN10.慢查询与 SQL 优化
mysql面试题01.索引问题02.事务与隔离级别03.锁机制04.存储引擎与性能优化05.用户权限、字符集与备份恢复
mysql实战01.EXPLAIN实战02.测试环境菜单误删排查与恢复03.MySQL IN 详解
网络
网络安全1.无线监听网卡苹果M系列虚拟机安装Kali Linux教程3.kali怎么使用RTL8812AU4.kali基础命令
网络基础进程之间怎样通过网络传递数据
网址常用网址
中间键
esElasticsearch 入门
mq
RabbitMQRabbitMQ高级RabbitMQ基础
1. MQ 基础2. MQ 核心角色与代码对应3. MQ Consumer Group 与消费模式4. SOFAMQ 账户变更代码实践5. MQ 可靠性问题6. 消息幂等
redis缓存击穿、穿透与雪崩Redis 分布式锁Redis 缓存问题Redis 数据结构
AI
使用说明
第三方插件&技能简介Archify使用与安装指南geekgeekRun使用OfferFlow使用指南Ponytail使用指南Skills Manager使用指南
CodexCodex CLI与IDE区别及使用指南Codex Hook单独配置与提交通知Codex MCP安装与使用指南Codex第三方插件安装与使用指南
Agent开发0-学习路线1.LLM、Token、上下文窗口与模型参数2.大模型 API、请求参数与响应结构3.Spring AI ChatClient4.Prompt、System Prompt、Prompt 模板6.结构化输出、JSON Schema7.SSE 流式响应8.会话 ID、聊天记录、Redis9.超时、重试、限流、降级10.*完成可运行聊天接口11.Function Calling、Tool Calling 原理12.用 Java 方法定义 Tool13.工具参数设计和校验14.实现订单查询工具15.实现物流查询工具16.实现库存查询工具17.多个工具自动选择18.工具异常、超时、重试
diy主机
主机零件学习1.CPU2.主板3.内存4.显卡5.硬盘6.散热7.风扇8.机箱热门型号价格表
捡垃圾diy-13600kf+5060diy-14600kf+5070
English高频词汇英文基础语法简单句子音标
GitGit常用命令Sublime Merge 使用指南
Java
工具库Caffeine本地缓存Reactor教程
工作实践如何使用@Async线程池使用与排查线上服务 CPU 使用率过高排查压测下RPC接口大量失败排查记录
基础1.HashMap2.ConcurrentHashMap3.HashSet4.final5.static6.volatile7.AtomicInteger8.String动态代理反射锁与线程同步线程注解
面试题1.HashMap 存储在方法内是线程安全的吗2.ArrayList参数传递与引用重新赋值3.== 和 equals 的区别、hashcode4.重载和重写的区别5.String、StringBuffer、StringBuilder区别及使用场景6.接口和抽象类7.ArrayList 与 LinkedList 的区别和扩容机制8.HashMap 和 Hashtable 的区别及底层实现9.Object 和 Objects 的区别10.ThreadLocal的原理和使用场景11.字节码是什么及作用12.Java类加载器有哪些13.双亲委派模型14.Java异常体系15.GC是什么16.GC如何判断对象可以被回收
面试总结0.HR面试模板1.面试一2.面试二3.面试三笔试
网络与 IO(黑马程序员-纯理论)01-网络编程基础02-IO模型与零拷贝03-BIO04-NIO基础与缓冲区05-NIO通道与选择器06-AIO
juc00-目录01-进程与线程02-线程同步与通信03-并发设计模式04-Java内存模型05-CAS与原子类06-ThreadLocal07-阻塞队列08-线程池使用与原理09-任务调度10-ForkJoin与享元模式11-AQS12-ReentrantLock13-读写锁14-并发协作工具15-ConcurrentHashMap16-CopyOnWrite与同步容器17-SkipListMap18-非阻塞队列
juc(工作常见)Java并发编程三个重点拆解
jvm1. JVM运行时数据区
Spring1.Spring IoC、DI与构造方法注入CGLIB、Byte Buddy 与 Spring AOPSpring 常用注解详解Spring Bean 生命周期
Spring MVC异常处理机制
linux常用命令
mac快捷键终端常用操作
python
基础01.Python是什么,为什么要安装Python02.Python项目中.venv是什么03.Python基础语法
基础实战sql替换
HTTPXHRMS员工详情接口调用(Python HTTPX)
windowswindows激活

一、💡 一句话理解

核心结论

接口定义“必须具备什么能力”,抽象类定义“同一类事物共有的状态和基础实现”。

记忆:接口看能力,抽象类看血缘和复用。

二、🧭 理论:它们是什么

2.1 接口

接口是一种引用类型,主要用来约定行为。类通过 implements 实现接口,并完成接口要求的方法。

interface Payable {
    void pay(int amount);
}

调用者只依赖 Payable,不需要关心具体使用支付宝、微信还是银行卡付款。

2.2 抽象类

抽象类用 abstract 修饰,不能直接创建对象,但可以被继承。它既能定义抽象方法,也能保存成员变量和已经实现的方法。

abstract class Payment {
    protected String orderNo;
 
    public Payment(String orderNo) {
        this.orderNo = orderNo;
    }
 
    public void printOrder() {
        System.out.println("订单号:" + orderNo);
    }
 
    public abstract void pay(int amount);
}

三、⚙️ 理论:核心区别

3.1 对比表

对比项接口抽象类
主要目的约定一种能力抽取同类对象的公共部分
关键字interface、implementsabstract class、extends
创建对象不能直接实例化不能直接实例化
方法可包含抽象、default、static 等方法可同时包含抽象方法和普通方法
成员变量字段默认是 public static final 常量可以保存普通实例状态
构造方法没有构造方法可以有构造方法,供子类初始化
继承数量一个类可以实现多个接口一个类只能直接继承一个类

3.2 怎么选择

  • 多种没有共同父类的对象都要具备同一种能力:使用接口。
  • 多个关系紧密的子类需要共享状态和代码:使用抽象类。
  • 两者可以一起使用:接口负责对外约定,抽象类负责复用公共实现。

常见误区

接口并不等于“只能写抽象方法”。现代 Java 接口可以有 default 和 static 方法;但接口仍不适合保存每个对象各自变化的实例状态。

四、🚀 实践:最小可运行示例

4.1 可以拿来干什么

支付系统需要统一调用不同支付方式,同时复用订单号打印逻辑:

  • Payable 接口规定支付能力。
  • BasePayment 抽象类保存订单号并提供公共方法。
  • WechatPayment 继承公共代码,实现具体支付逻辑。

4.2 完整代码、启动和验证

文件:Demo.java

// 接口只约定支付能力,调用方可以面向接口编程。
interface Payable {
    void pay(int amount);
}
 
// 抽象类实现接口,但可以暂时不实现 pay,由具体子类完成。
abstract class BasePayment implements Payable {
    // 抽象类可以保存每个支付对象自己的订单号。
    protected final String orderNo;
 
    // 构造方法供子类初始化公共状态。
    protected BasePayment(String orderNo) {
        this.orderNo = orderNo;
    }
 
    // 普通方法直接复用,不要求每个子类重复编写。
    public void printOrder() {
        System.out.println("订单号:" + orderNo);
    }
}
 
class WechatPayment extends BasePayment {
    public WechatPayment(String orderNo) {
        super(orderNo);
    }
 
    @Override
    public void pay(int amount) {
        System.out.println("微信支付:" + amount + " 元");
    }
}
 
public class Demo {
    public static void main(String[] args) {
        WechatPayment payment = new WechatPayment("ORDER-1001");
        payment.printOrder();
 
        // 接口类型可以接收任意 Payable 实现,方便以后替换支付方式。
        Payable payable = payment;
        payable.pay(100);
    }
}

运行:

javac Demo.java
java Demo

预期输出:

订单号:ORDER-1001
微信支付:100 元

五、🎤 面试时怎么流利地说

5.1 回答路线

先说用途,再对比状态、方法、构造方法和继承数量,最后说明选择场景。

5.2 30 秒标准回答

接口主要用来定义能力和行为规范,一个类可以实现多个接口;抽象类主要用于关系紧密的子类之间复用状态和代码,一个类只能直接继承一个类。两者都不能直接实例化,也都可以包含抽象方法。如果只想约束行为,我会选择接口;如果还需要共享成员变量、构造逻辑和公共实现,我会选择抽象类。实际开发中也经常把两者结合使用。

5.3 高频追问与短答

  • **抽象类一定有抽象方法吗?**不一定。只要类被 abstract 修饰,它就是抽象类,也不能直接实例化。
  • **接口可以有方法实现吗?**可以,例如 default 和 static 方法。
  • **抽象类可以实现接口吗?**可以。如果没有实现接口的全部抽象方法,该类继续声明为抽象类即可。
  • **为什么接口支持多个,类继承只支持一个?**Java 允许一个类实现多个接口,从而获得多种类型能力;但一个类只能直接继承一个类,避免多份实例状态和实现带来的冲突。

六、📌 总结

  • 接口强调“能做什么”,抽象类强调“是什么以及共用什么”。
  • 接口适合解耦和扩展,抽象类适合共享状态和代码。
  • 一个类可以实现多个接口,但只能直接继承一个类。
  • 两者不是互斥关系,可以组合使用。
  • 相关知识:4.重载和重写的区别。

七、🔗 官方资料