1132 字
约 3 分钟
5
S04-B06 · 接口、抽象类、Lambda 与枚举
适用读者:分不清"该用接口还是抽象类"的人。
前置:S04-B05。
实测环境:OpenJDK 21.0.12.1(2026-11-05)。
覆盖旧文:A-1655(165) A-1717(101) A-1765(82) A-1718(92) A-1771(48) = 488 点。
覆盖扩展:E-S04-007(函数式接口与 default 方法)。
上一篇:S04-B05 · 封装、继承与多态:到底在解决什么问题
下一篇:S04-B07 · 异常处理。
1. 一句话结论
接口定义"能做什么"(契约,可多实现),抽象类定义"是什么"(部分实现,只能单继承)。Lambda 是"只有一个抽象方法的接口"的简写。
| 维度 | 接口 | 抽象类 |
|---|---|---|
| 多重继承 | ✅ 可实现多个 | ❌ 只能继承一个 |
| 状态(字段) | 只能是 public static final 常量 |
可有实例字段 |
| 构造器 | ❌ 没有 | ✅ 有 |
| 方法实现 | default / static / private(Java 9+) |
普通方法与抽象方法 |
| 语义 | can-do(能力) | is-a(分类) |
2. 接口的演进:default 方法(E-S04-007)
interface Greeter {
String name();
default String greet() { return "Hello, " + name(); } // 默认实现
static Greeter of(String n) { return () -> n; } // 静态工厂
}
| 能力 | 解决的问题 |
|---|---|
default |
给接口加方法而不破坏已有实现(Java 8 引入的核心动机) |
static |
接口内提供工具方法 |
private(9+) |
多个 default 方法复用代码 |
| 函数式接口 | @FunctionalInterface:只有一个抽象方法 → 可用 Lambda |
判据:"加这个方法会不会破坏现有实现?" 会 → 用 default。
3. Lambda:语法糖,但有三条边界
// 等价的两段代码
Greeter g1 = new Greeter() { public String name() { return "A"; } };
Greeter g2 = () -> "A";
| 边界 | 说明 |
|---|---|
| 只能用于函数式接口 | 有 1 个抽象方法(default 不算) |
| 捕获变量必须 effectively final | 不能改外部局部变量(与 S09-B07 的闭包对比) |
this 指向外部类 |
与匿名内部类不同(匿名类 this 指自身) |
实测对照(S09 的 Go 闭包):Go 捕获变量本身(可变),Java 只能捕获 final 的值——Java 用限制换来了更少的并发/作用域陷阱。
4. 枚举:比 static final int 强在哪
enum Status {
NEW("新建"), PAID("已付"), SHIPPED("已发");
private final String label;
Status(String l) { this.label = l; }
public String label() { return label; }
}
| 能力 | 说明 |
|---|---|
| 类型安全 | 不能传非法值(对比 int) |
| 可带字段与方法 | 每个常量可有自己的实现(匿名子类) |
values() / valueOf() |
遍历与解析 |
| 天然单例 | Status.NEW 全局唯一 → 适合做单例(比双重检查更安全) |
| switch 友好 | 编译期检查完备性 |
5. Optional:表达"可能没有"(A-1718)
| 用法 | 说明 |
|---|---|
Optional.of(x) |
不允许 null |
Optional.ofNullable(x) |
允许 null |
map/filter/flatMap |
链式处理 |
orElse/orElseGet/orElseThrow |
兜底 |
反模式:
| 反模式 | 原因 |
|---|---|
字段用 Optional |
不可序列化、增加内存开销 |
方法参数用 Optional |
调用方仍要判空 |
optional.get() 不判 isPresent |
相当于换个方式 NPE |
判据:Optional 用于"返回值",表示"可能查不到",不要用于字段与参数。
6. 五个误区
| 误区 | 真相 |
|---|---|
| "接口不能有方法体" | default/static/private 都可以 |
| "抽象类比接口强" | 接口可多实现;抽象类可持有状态 |
| "Lambda 能改外部变量" | 必须 effectively final |
| "枚举只是常量集合" | 可带字段/方法/接口实现 |
"Optional 到处用更安全" |
字段/参数用它会增加复杂度 |
7. 自检
- 接口与抽象类的选择判据?
default方法解决了什么问题?- Lambda 的三个边界是什么?
- 枚举相比
static final int的优势(至少三条)? Optional该用在哪、不该用在哪?
8. 下一篇
S04-B07 · 异常处理:分类、最佳实践与常见反模式
抽象层讲完,下一篇讲"出错怎么办":受检 vs 非受检、finally 的陷阱、try-with-resources。
本篇属于系列《S04 · Java 语言核心》。旧文来源:A-1655/1717/1765/1718/1771;扩展点 E-S04-007。
S04-B06 · 接口、抽象类、Lambda 与枚举
https://www.clxhxhhr.top/posts/5221/ 评论
0 条
还没有评论,先写一条吧。