核心是定位违反密封契约的层级:Java需显式声明permits且子类必须标注final/sealed/non-sealed,Kotlin要求所有子类与sealed类同文件;任一层修饰符缺失、位置错误或permits不匹配均导致编译中断。

处理这类编译链报错,核心不是“解开嵌套”,而是**定位哪一层违反了密封契约**。密封类的约束是刚性的:它不关心复杂度,只认规则是否被严格执行。只要某一层子类没按要求声明、位置不对、修饰符缺失或 permits 不匹配,整个继承链就会在编译期中断。
检查密封类定义层是否完整声明 permits(Java)或同文件约束(Kotlin)
这是最常见断点。Java 中 sealed 类必须显式列出所有直接子类;Kotlin 中所有子类必须与 sealed class 在同一文件中(不能仅靠 import 或跨文件继承)。
- Java:确认 sealed 类签名含 permits A, B, C,且列表中每个类名拼写完全一致、大小写敏感、无多余空格
- Kotlin:打开密封类所在文件,逐行检查所有子类——data class、object、class 都必须物理存在于该文件内,不能只是“看起来像”在同一个包里
- 特别注意嵌套类:若子类本身是内部类(如
Outer.SealedParent的子类),则其声明也必须在Outer所在文件中,且需用Outer.SubClass : Outer.SealedParent()形式
验证每层子类是否正确使用限定修饰符
密封体系是逐层生效的。上层 sealed 只管直接子类,但这些子类自己若也声明为 sealed,则它们的子类同样受约束——任何一层遗漏修饰符都会导致编译失败。
- Java:每个被
permits列出的类,必须明确标注 final、sealed 或 non-sealed ——三者缺一不可,不能省略,也不能用public或abstract替代 - Kotlin:子类无需额外修饰符,但若子类自身也是 sealed,则它的子类仍须与它同文件;不能出现 “sealed class A → class B : A() → sealed class C : B()” 且 C 在另一文件的情况
- 警惕中间层“伪装开放”:例如用
open class Middle : SealedParent()作跳板再让其他类继承 Middle——这在 Java/Kotlin 中均非法,会直接触发 “not allowed to inherit” 错误
排查模块与可见性冲突(尤其跨模块/跨包场景)
Java 25 起强化了模块级密封控制,Kotlin 虽无模块概念,但对 internal / private 成员的访问限制同样会影响密封链。
- Java:确保密封类及其所有 permitted 子类位于同一命名模块(
module-info.java中已声明 exports 或 opens),且子类未被requires static等弱依赖方式间接引入 - Kotlin:若密封类为
internal,其子类也必须是internal;若为private(仅限嵌套场景),子类只能是其内部对象或类,不可提升为 top-level - 记录类(record)参与时:Java 中 record 必须显式出现在
permits列表中,且声明为final record MyRecord(...) implements SealedInterface,不能省略final
用编译器提示反向追踪断点位置
不要从顶层开始逐行看代码。直接看报错信息里的类名和行号,它通常精准指向违规点。
- 错误如 “Class 'X' is not allowed to inherit from sealed class 'Y':立刻检查 X 是否在 Y 的
permits列表中(Java)或是否与 Y 不在同一文件(Kotlin) - 错误如 “illegal combination of modifiers”:聚焦 X 类的 class 声明行,确认修饰符组合合法(Java:只能 final/sealed/non-sealed 三选一;Kotlin:sealed 子类不可加 open/abstract)
- 错误如 “Non-exhaustive when expression”(Kotlin):说明密封类定义没问题,但调用处漏分支——此时问题不在继承链,而在消费端,需补全
when分支

















