java密封类通过permits强制指定直接子类,必须在同一模块或包中,且子类须声明为final、sealed或non-sealed;permits是编译期白名单,不支持通配符或动态配置。

Java 的密封类(Sealed Classes)通过 permits 明确列出哪些类可以继承它,从而严格控制类的继承关系。这不是可选的修饰,而是强制要求——只要声明为 sealed,就必须用 permits 指定所有允许的直接子类。
permits 必须写在 sealed 类声明的同一行或紧随其后
permits 是 sealed 类声明的一部分,语法位置固定:紧跟在类头的花括号前,用逗号分隔子类名。子类必须与密封类在同一个模块中(或同一包下,若未使用模块系统),且必须显式声明为 final、sealed 或 non-sealed。
- 正确写法示例:
public sealed class Shape permits Circle, Rectangle, Triangle { } - 错误写法:
public sealed class Shape { } // 缺少 permits,编译失败public sealed class Shape permits Circle Rectangle { } // 缺少逗号,语法错误
permits 列出的子类必须真实存在且可访问
编译器会检查 permits 中每个类是否已定义、是否为该密封类的**直接子类**、是否满足继承约束。如果某个类不存在、不是 public(且不在同一包)、或未正确声明继承修饰符,都会导致编译错误。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
Circle必须是class Circle extends Shape,且需加上final(如final class Circle extends Shape)或其他有效修饰符 - 若
Rectangle是另一个sealed类(比如允许多边形变体),它自己也要有对应的permits - 若想让某个子类还能被进一步扩展,就用
non-sealed class Triangle extends Shape
permits 不支持通配符或运行时动态控制
permits 是编译期硬编码的白名单,不能写成字符串数组、不能通过配置文件加载、也不能用反射绕过。JVM 在加载类时会验证继承链是否符合密封声明,违反即抛 IncompatibleClassChangeError。
- 不能写
permits *或permits "com.example.shapes.*" - 不能在子类里用
public class UnknownShape extends Shape—— 即使不实例化,编译阶段就会报错 - 模块系统下,若子类在另一模块,需在
module-info.java中用opens或exports配合,但permits本身仍只写类名
常见组合:sealed + final / sealed / non-sealed 子类
每个 permits 列出的子类必须明确自身对继承的立场:
- final:彻底禁止继承(最常用,适合确定不变的实现)
-
sealed:自身也是密封类,继续限制下级子类(适合分层建模,如
Expression→BinaryExpr→AddExpr/MulExpr) - non-sealed:开放继承,任何类都可继承它(慎用,仅当需要插件式扩展时)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










