[Java学习日记07】聊聊接口和抽象类

前言:关于"套娃"代码的终极拷问

坐标:图书馆 5 楼(靠空调位,今天风很大)

状态:刚改完一个被无限层级继承搞崩的 Bug。

碎碎念: 兄弟们,今天我彻底破防了。 本来想给我的项目加个新功能,结果发现原作者(也就是上个月的我)写了一堆深不见底的继承。我想改个方法,结果十几个子类全报错。 学长过来看了一眼,摇摇头说:"你这设计,属于是'过度继承',这种场景你应该用接口(Interface)而不是抽象类(Abstract Class)啊。"

回来后我反思了很久。原来这两者虽然都能用来"被继承",但底层逻辑完全不同。今天咱就来聊聊这两大"模板",看看它们到底怎么选!

🚀 目录

  1. [抽象类 (Abstract Class):未完成的"毛坯房"](#抽象类 (Abstract Class):未完成的“毛坯房”)

    • 1.1 什么是抽象类?

    • 1.2 它是为了"共性"而生

  2. [接口 (Interface):一份必须遵守的"协议"](#接口 (Interface):一份必须遵守的“协议”)

    • 2.1 什么是接口?

    • 2.2 它是为了"扩展"而生

  3. 核心对撞:一张表分胜负

  4. [哲学思考:is-a 与 has-a 的博弈](#哲学思考:is-a 与 has-a 的博弈)

    • 4.1 抽象类是"亲爹"

    • 4.2 接口是"考证"

  5. [JDK 8 之后的"叛变":接口居然能写实现了?](#JDK 8 之后的“叛变”:接口居然能写实现了?)

  6. 大厂面试:什么时候该用哪一个?

  7. 结语:代码的优雅在于克制

1. 抽象类 (Abstract Class):未完成的"毛坯房"

生活化场景: 学校要开发一个"学生管理系统"。所有学生(无论是 CS 的、经管的、还是艺术的)都有学号、名字,都要选课。 但不同专业的学生"写作业"的方式完全不一样。

这时候,我们可以搞一个 Student抽象类

1.1 什么是抽象类?

它是一个半成品

  • 它不能被 new 出来(你见过一个纯粹的、没有任何属性的"学生"对象吗?没有,他必须是某个具体的专业生)。

  • 它里面可以有已经写好的方法(大家共用的,比如 sleep()),也可以有没写完的方法(abstract 方法,比如 study())。

1.2 它是为了"共性"而生

抽象类强调的是**"身份(Identity)"**。它是子类的模板,子类是对它的细化。

复制代码
abstract class Student {
    String name;
    
    // 共性方法:大家都得睡觉
    void sleep() {
        System.out.println("在图书馆睡着了...");
    }
    
    // 抽象方法:具体怎么学,子类自己定
    abstract void study();
}

2. 接口 (Interface):一份必须遵守的"协议"

生活化场景: 不论你是学生、老师,还是校外的路人。只要你想进校门,你就得有"进校证(CanEnterSchool)"。 这个证件规定你必须具备"刷码(swipeCard)"和"出示健康信息(showInfo)"的功能。

2.1 什么是接口?

它是一份契约 或者规范

  • 接口只管"能干什么",不管"怎么干"。

  • 它里面全都是没有实现的"大饼"(除非是 JDK 8 以后的 default 方法)。

2.2 它是为了"扩展"而生

接口强调的是**"功能(Ability)"**。一个类可以实现多个接口。

  • 大学生比喻:我可以是一个"学生(抽象类继承)",同时我也可以拥有"英语四级(接口实现)"、"驾照(接口实现)"。

    interface DrivingLicense {
    void drive(); // 只要有驾照,你就得会开车
    }

3. 核心对撞:一张表分胜负

特征 抽象类 (Abstract Class) 接口 (Interface)
关键字 abstract class interface
关系 extends (继承) implements (实现)
数量 单继承(只能有一个亲爹) 多实现(可以考很多证)
变量 可以有普通变量 只能是常量 (public static final)
构造器 (供子类调用)
方法 可以有具体实现,也可以抽象 以前全是抽象,现在可以有 default

4. 哲学思考:is-a 与 has-a 的博弈

这是理解两者的灵魂所在。

4.1 抽象类是"is-a"

如果你觉得 A 是一个 B,那就用抽象类。

  • 是一个 动物。

  • CS学生 是一个 学生。

4.2 接口是"has-a"或"like-a"

如果你觉得 A 具有某种功能,那就用接口。

  • 具有 爬树的能力。

  • 这个类 具有 被序列化的能力(Serializable)。

5. JDK 8 之后的"叛变":接口居然能写实现了?

在很久以前,接口是纯粹的。但从 JDK 8 开始,为了支持 Lambda 表达式和方便版本升级,接口里可以写 default 方法和 static 方法了。

这就尴尬了:接口越来越像抽象类了? 其实不然。即便接口能写实现,它依然没有状态(成员变量) ,依然支持多实现。这些核心本质没变。

6. 大厂面试:什么时候该用哪一个?

面试官最喜欢问:"既然接口现在能写实现,那还要抽象类干嘛?"

你可以这样装杯(回怼)

  1. 如果你需要定义子类的共同属性(比如名字、年龄),抽象类是唯一的选择,因为接口不能存数据(只有常量)。

  2. 如果你需要约束不同类别的行为(比如灯能开关、电视也能开关),请用接口。

  3. 如果你想预留后路,建议用接口。因为 Java 是单继承,用了抽象类就把"亲爹位"占了,以后想改就难了。

7. 结语

写完这篇日记,我终于把之前的"套娃"代码重构完了。 我把那些乱七八糟的继承改成了接口组合,代码瞬间感觉清爽了许多。

作为大学生的我们:

  • 抽象类教我们要有深度(扎实的根基)。

  • 接口教我们要有广度(多样的技能)。

如果你也被"到底用哪个"纠结过,点个赞支持一下!下期咱们聊聊Java的异常体系

相关推荐
咖啡八杯14 小时前
GoF设计模式——策略模式
java·后端·spring·设计模式
用户128526116021 天前
我把祖传Java项目重构后,接口响应从3s砍到了200ms,只改了这几行代码
java
Linsk1 天前
组件 = 模板 + 业务逻辑
java·前端·vue.js
星沉远浦1 天前
用Gemini高效解决Java代码报错难以定位的问题
java
用户298698530141 天前
Word 文档字符级格式化:Java 实现方案详解
java·后端
笨鸟飞不快1 天前
从单个服务到集群:一次完整的性能排查复盘
java·前端
荣码1 天前
用Streamlit给AI应用套个界面,10行代码出Web页面
java·python
SamDeepThinking1 天前
Java微服务练习方式
java·后端·微服务
朦胧之2 天前
AI 编程-老项目改造篇
java·前端·后端
程序猿大帅2 天前
别再只当调包侠了:用 Spring AI 落地 Function Calling,我被大模型硬生生砸出了三个大坑
java