首页/新闻资讯/正文详情

抽象类和接口的区别完整示例

发布时间:2026/9/22 9:39:08 来源:云帆数科 栏目:资讯中心
抽象类和接口的区别完整示例
抽象类和接口区别详解:Java避坑指南与实战案例 刚接手新项目,环境配置卡半天,代码一跑就报错,是不是特别熟悉?别慌,这种“抽象类和接口区别”的坑,我踩过三次才彻底搞懂。今天这份避坑指南,直接给你能跑的代码和真实踩坑记录,省得你再去CSDN翻半天帖子。 项目目标 咱们不整虚的,直接上项目。目标是实现一个“支付系统”模块,支持微信、支付宝两种支付方式。这里有个经典坑:一开始我用抽象类统一封装,结果加支付宝时,微信的逻辑被污染了;改用接口后,扩展性直接拉满。 项目核心需求:定义统一的支付行为 支持动态扩展新支付方式 避免代码重复,降低耦合度目录结构 先看结构,心里有底再动手: payment-system/ ├── src/main/java/com/example/payment/ │ ├── api/ │ │ ├── PaymentService.java # 接口:定义支付行为 │ │ └── RefundService.java # 接口:定义退款行为 │ ├── abstract/ │ │ └── AbstractPayment.java # 抽象类:封装通用逻辑 │ ├── impl/ │ │ ├── WechatPayment.java # 微信支付实现 │ │ └── AlipayPayment.java # 支付宝实现 │ └── Main.java # 测试入口 └── pom.xml注意:api 和 abstract 分开放,这是避坑关键。混在一起,后期改一处崩一片。 核心代码实现 1. 接口定义:行为契约 // PaymentService.java package com.example.payment.api;public interface PaymentService {// 抽象方法:必须实现void pay(String orderId, double amount);// 默认方法:Java 8+,可选实现default void verifySignature(String signature) {System.out.println(签名验证通过: + signature);} }逐行讲解:pay() 是抽象方法,子类必须实现,这是接口核心价值:定义“能做什么”,不关心“怎么做”。 verifySignature() 是默认方法,避免所有实现类重复写相同逻辑。这是Java 8后接口的大升级,CSDN上很多老教程还没覆盖这点。2. 抽象类封装:通用逻辑 // AbstractPayment.java package com.example.payment.abstract;import com.example.payment.api.PaymentService; import java.util.Date;public abstract class AbstractPayment implements PaymentService {// 通用字段protected String merchantId;protected String apiKey;// 构造器:强制传入必要参数public AbstractPayment(String merchantId, String apiKey) {this.merchantId = merchantId;this.apiKey = apiKey;}// 模板方法:封装通用流程public void executePayment(String orderId, double amount) {validateOrder(orderId, amount); // 1. 验证doPay(orderId, amount); // 2. 执行具体支付(子类实现)logPayment(orderId, amount); // 3. 记录日志}// 具体方法:通用验证逻辑protected void validateOrder(String orderId, double amount) {if (orderId == null || orderId.isEmpty()) {throw new IllegalArgumentException(订单ID不能为空);}if (amount = 0) {throw new IllegalArgumentException(金额必须大于0);}}// 抽象方法:子类必须实现protected abstract void doPay(String orderId, double amount);// 具体方法:通用日志protected void logPayment(String orderId, double amount) {System.out.printf([%s] 支付成功:订单%s,金额%.2f%n, new Date(), orderId, amount);} }逐行讲解:executePayment() 是模板方法,固定流程:验证→支付→日志。子类只需关心doPay()。 validateOrder() 是具体方法,所有支付方式共享,避免重复代码。 doPay() 是抽象方法,强制子类实现具体支付逻辑。 关键区别:抽象类可以有状态(字段)、构造器、具体方法;接口(Java 8前)只能有抽象方法和常量。3. 具体实现:微信和支付宝 // WechatPayment.java package com.example.payment.impl;import com.example.payment.abstract.AbstractPayment;public class WechatPayment extends AbstractPayment {public WechatPayment(String merchantId, String apiKey) {super(merchantId, apiKey);}@Overrideprotected void doPay(String orderId, double amount) {System.out.println(调用微信API,订单: + orderId + ,金额: + amount);// 实际项目中这里调用微信SDK}@Overridepublic void pay(String orderId, double amount) {executePayment(orderId, amount); // 复用模板方法} }// AlipayPayment.java package com.example.payment.impl;import com.example.payment.abstract.AbstractPayment;public class AlipayPayment extends AbstractPayment {public AlipayPayment(String merchantId, String apiKey) {super(merchantId, apiKey);}@Overrideprotected void doPay(String orderId, double amount) {System.out.println(调用支付宝API,订单: + orderId + ,金额: + amount);// 实际项目中这里调用支付宝SDK}@Overridepublic void pay(String orderId, double amount) {executePayment(orderId, amount); // 复用模板方法} }4. 测试入口 // Main.java package com.example.payment;import com.example.payment.impl.WechatPayment; import com.example.payment.impl.AlipayPayment; import com.example.payment.api.PaymentService;public class Main {public static void main(String[] args) {// 依赖接口,不依赖具体实现PaymentService wechat = new WechatPayment(WX001, key123);PaymentService alipay = new AlipayPayment(ALI001, key456);wechat.pay(ORDER1001, 99.99);alipay.pay(ORDER1002, 199.99);// 测试默认方法wechat.verifySignature(sig_abc);} }运行输出: [2024-01-15 10:30:00] 支付成功:订单ORDER1001,金额99.99 调用微信API,订单:ORDER1001,金额:99.99 [2024-01-15 10:30:00] 支付成功:订单ORDER1002,金额199.99 调用支付宝API,订单:ORDER1002,金额:199.99 签名验证通过:sig_abc运行与测试 环境配置最容易卡人。我用的JDK 17,Maven 3.8.6,pom.xml如下: dependencies!-- 单元测试 --dependencygroupIdjunit/groupIdartifactIdjunit/artifactIdversion4.13.2/versionscopetest/scope/dependency /dependencies单元测试代码: @Test public void testWechatPayment() {PaymentService service = new WechatPayment(WX001, key123);service.pay(TEST001, 50.0);// 断言日志输出,实际项目中用Mockito }常见报错:Cannot instantiate interface PaymentService:你直接new接口了,接口不能实例化,必须用实现类。 Abstract class cannot be instantiated:你new抽象类了,抽象类也不能直接实例化。优化扩展 1. 多接口组合:解耦更彻底 如果退款逻辑和支付逻辑强耦合,扩展性差。拆成两个接口: // RefundService.java public interface RefundService {void refund(String orderId, double amount); }让WechatPayment同时实现两个接口: public class WechatPayment extends AbstractPayment implements RefundService {@Overridepublic void refund(String orderId, double amount) {System.out.println(微信退款:订单 + orderId + ,金额 + amount);} }好处:支付和退款独立演进,加新支付方式时,退款逻辑可以复用。 2. 静态方法:工具类场景 Java 8+接口支持静态方法,适合放工具逻辑: public interface PaymentUtils {static boolean isValidAmount(double amount) {return amount 0 amount 1000000;} }3. 抽象类vs接口:选择决策树场景 推荐 原因需要共享状态/构造器 抽象类 接口不能有实例字段定义行为契约 接口 更轻量,支持多实现模板方法模式 抽象类 可封装通用流程动态扩展行为 接口 类只能继承一个抽象类避坑提示:别滥用抽象类。我见过一个项目,抽象类塞了20个具体方法,改一处影响所有子类。接口+组合更灵活。 小结 抽象类和接口的区别,核心就三点:抽象类:有状态、有构造器、可封装通用逻辑,但只能单继承。 接口:纯行为契约(Java 8后可有默认/静态方法),支持多实现,更解耦。 实战选择:需要共享状态和流程用抽象类,定义行为契约用接口。两者常配合使用,如本文案例。这个知识点你面试被问过吗?留言说说

相关推荐

搞懂什么是王道:3个真实案例拆解新手避坑指南
搞懂什么是王道:3个真实案例拆解新手避坑指南

搞懂什么是王道:3个真实案例拆解新手避坑指南 刚入行水利工程设计或施工,是不是经常听到老法师们念叨“什么是王道”?别误会,这里指的绝不是那套著名的考研数学复习资料,也不是武侠小说里的武林秘籍。在咱们这个讲究资质、证书和项目经验的硬通货行业里… · 2026/9/22 9:38:55

DeepLearning4J 的 Omnihub 模型下载与转换 SDK:跨框架模型 Zoo 的统一下载、冻结与部署指南
DeepLearning4J 的 Omnihub 模型下载与转换 SDK:跨框架模型 Zoo 的统一下载、冻结与部署指南

深度学习人工智能机器学习分布式训练 【免费下载链接】deeplearning4j Suite of tools for deploying and training deep learning models using the JVM. Highlights include model import for keras, tensorflow, and onnx/pytorch, a modular and tiny c library for runnin… · 2026/9/22 9:38:49

5分钟吃透合金装备雷电机制,程序员速查手册避坑指南
5分钟吃透合金装备雷电机制,程序员速查手册避坑指南

5分钟吃透合金装备雷电机制,程序员速查手册避坑指南 别再去啃那几千行的官方文档了,抓不住重点? 很多后端开发在看《合金装备》系列代码结构时,容易陷入细节泥潭。 这份 速查手册 ,直接带你拆解雷电角色的核心状态机逻辑。… · 2026/9/22 9:38:36

3分钟吃透昆特算法最佳实践面试突击
3分钟吃透昆特算法最佳实践面试突击

3分钟吃透昆特算法最佳实践面试突击 官方文档动辄几百页,看完脑子还是浆糊?别急,直接看这篇【昆特】算法最佳实践。 很多刚入行的同学,面对“昆特”这种听起来高大上的概念,第一反应是打开官方Wiki。结果呢?看了半小时,只记住了“分布式一致性”… · 2026/9/22 10:14:23

国产模型包揽前三:DeepSeek V4.1 Flash首次登顶OpenRouter周榜
国产模型包揽前三:DeepSeek V4.1 Flash首次登顶OpenRouter周榜

截至9月20日的OpenRouter周度榜单,出现了一个标志性的变化。DeepSeek V4.1 Flash以15.8万亿Token首次登顶周榜第一,环比增长219%。智谱GLM 5.3 Flash以14.1万亿Token位居第二,腾讯Hy4 preview以12.5万亿Token排名第三。GPT-5.6 Luna跌至第四&… · 2026/9/22 10:14:17

模型连不上?Claude Code 安装时把 ANTHROPIC_BASE_URL 改到 TaoToken 通道
模型连不上?Claude Code 安装时把 ANTHROPIC_BASE_URL 改到 TaoToken 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/22 10:14:11

笔记本和超级本避坑速查手册:3个致命报错救急指南
笔记本和超级本避坑速查手册:3个致命报错救急指南

笔记本和超级本避坑速查手册:3个致命报错救急指南 官方文档几百页看进去全是云里雾里,关键报错找不到重点,真的能把人逼疯。 别慌,这份【笔记本和超级本】避坑速查手册,直接把你常踩的坑和修复代码甩出来。… · 2026/9/22 10:14:05

OpenSumi 适配 VS Code v1.60.0 API,Codex 侧 Base URL 填 TaoToken
OpenSumi 适配 VS Code v1.60.0 API,Codex 侧 Base URL 填 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/22 10:13:59

3步搞定梦幻西游挤线器性能瓶颈含完整示例
3步搞定梦幻西游挤线器性能瓶颈含完整示例

3步搞定梦幻西游挤线器性能瓶颈含完整示例 官方文档翻了三遍,关键参数还是没看懂?别急,这里直接上 完整示例 ,3秒定位卡顿根源。… · 2026/9/22 10:13:46

5个电影海报图片处理坑,新手避坑指南
5个电影海报图片处理坑,新手避坑指南

5个电影海报图片处理坑,新手避坑指南 刚写完代码,一运行屏幕直接炸了。满屏红色的 StackTrace 滚得比弹幕还快,什么 NullPointerException 、 ImageIO.read() returned null 、… · 2026/9/22 0:00:07

注册微信公众账号:一文搞懂从0到1全流程
注册微信公众账号:一文搞懂从0到1全流程

注册微信公众账号:一文搞懂从0到1全流程 复制来的代码跑不通,报错信息满屏飞,到底卡在哪?别急,咱们先停下手里的调试。很多开发者觉得注册微信公众账号只是填个表单、传个身份证那么简单,真上手才发现坑深不见底。今天这篇 一文搞懂… · 2026/9/22 0:00:07

手写实现图片压缩网站核心:搞定WebP转换与质量调优
手写实现图片压缩网站核心:搞定WebP转换与质量调优

手写实现图片压缩网站核心:搞定WebP转换与质量调优 复制来的代码跑不通不知道怎么调?别慌,这种“复制粘贴地狱”在开发圈太常见了。尤其是做 图片压缩网站… · 2026/9/22 0:00:19

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码