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. 自检

  1. 接口与抽象类的选择判据?
  2. default 方法解决了什么问题?
  3. Lambda 的三个边界是什么?
  4. 枚举相比 static final int 的优势(至少三条)?
  5. 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/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。