这是专栏第 5 篇。sealed对我来说不是语法好看,而是架构治理工具: 它把“谁可以扩展我”从约定变成编译期约束。一、我为什么会持续踩“继承失控”的坑JDK 8 时代,抽象类和接口默认都是开放继承。问题不是“不能扩展”,而是“任何地方都能扩展”,久而久之会出现三件事:继承树越来越大,但没人能完整列出所有实现;逻辑分发点(if/else、switch、工厂)逐渐和真实子类集合脱节;一次变更的影响面很难评估。我做过一个事件模型重构,光定位所有子类就花了不少时间。sealed的价值就是把这件事前置到编译期。二、版本信息(含 JEP)JEP 360:Java 15(预览)JEP 397:Java 16(第二次预览)JEP 409:Java 17(正式)如果是生产项目,我建议直接用 JDK 17/21 的正式特性。三、sealed的核心语义sealed的重点只有一句话:父类/接口明确声明允许哪些子类型继承或实现。同时,每个允许的子类必须显式说明自己是:final(到此为止,不再扩展)sealed(继续受控扩展)non-sealed(从这里重新开放)也就是说,继承边界变成了可读、可审查、可编译校验的契约。四、适配场景 / 不适配场景适配场景:有限变体模型(命令、事件、支付结果、状态机节点);需要做穷举处理,希望编译器帮助兜底;安全敏感逻辑,希望限制扩展入口。不适配场景:插件式架构,业务方要动态扩展实现;对外 SDK 需要长期开放继承;强依赖运行时代理/动态字节码扩展的旧框架。五、从 JDK 8 升级时,我重点看这 7 件事1) 版本策略15/16 的sealed是预览能力,需--enable-preview;17+ 正式可用。项目内不要混用“部分模块预览、部分模块正式”的状态。2)permits与模块边界被permits列出的子类必须满足同模块或同包等约束(具体取决于模块化结构)。拆模块前要先画清楚继承关系。3) 子类修饰符补全每个子类都必须声明final/sealed/non-sealed。这一步是很多迁移 PR 容易漏的地方。4) 框架兼容像序列化、反序列化、ORM 映射这类框架,遇到受限继承时要做一次端到端验证。5) 反射与注册逻辑如果你的系统靠 classpath 扫描“自动发现实现类”,改成sealed后建议加显式注册或测试校验,防止遗漏。6) 分支处理策略把业务分发逻辑和sealed体系一起改,避免出现“继承收紧了,处理分支还是开放式兜底”的不一致。7) 回滚路径首批只在一个包或一个领域模型试点,保留回滚分支,不建议一次性全仓改造。六、落地方式(我会怎么推进)先挑一个“有限集合”最明显的模型做试点;把父类改成sealed,列出明确permits;同步改写工厂或分发逻辑,补穷举测试;用 CI 校验“新增子类是否同步更新分发逻辑”。七、新旧写法对比(1):开放继承 vs 受控继承JDK 8 常见写法: