= GEP-13: 密封类 :icons: font .Metadata **** [horizontal,options="compact"] *编号*:: GEP-13 *标题*:: 密封类 *版本*:: 1 *类型*:: 功能 *状态*:: 草稿 *负责人*:: Paul King *创建日期*:: 2021-07-22 *最后修改日期* :: 2021-07-22 **** == 摘要:密封类 密封类和接口限制了哪些其他类或接口可以扩展或实现它们。通过支持密封类和接口,Groovy 编程语言可以提供一种额外的机制来控制类层次结构构建。 === 动机 继承是创建相关类和接口层次结构的强大机制。有时,需要限制此类层次结构中子代的定义。修饰符已经提供了一些机制: * 如果我们所有的类和接口都是公共的,这表明我们希望最大程度地重用。 * `final` 修饰符提供了一种在方法或类级别限制进一步继承的机制。它有效地限制了所有进一步的扩展,并表明不再需要进一步的代码重用。 * 通过将基类设置为包私有,我们可以将扩展限制为仅限于同一包中的类。如果一个抽象的 `Shape` 类是包私有的,我们可以在同一个包中拥有公共的 `Square` 和 `Circle` 类。这表明我们希望代码重用仅在包内发生。虽然它确实限制了在原始包之外创建新形状,但它没有为可以是正方形或圆形的形状提供抽象,因为 `Shape` 不是公共的。 * 我们可以使用 `protected` 可见性将成员访问严格限制为子代,但这并不能帮助我们解决上述问题,例如在讨论的示例中 `Shape` 缺乏可见抽象。 密封类或接口可以是公共的,但有一个相关的允许子代列表。不在该列表中的类或接口不能继承这些密封类型。这表明我们希望在层次结构内重用代码,但不能超越。层次结构中的父类可以变得“可访问”,而无需同时使其“可扩展”。这允许创建层次结构,在内部实现最大程度的重用,而无需为以后任意添加的扩展进行防御性编码。此类对于定义代数数据类型(ADT)和在需要考虑是否已涵盖所有可能类型的情况(例如,如果 switch 块未通过各自的 case 分支穷尽地覆盖所有可能类型,静态编译器可能希望发出警告)很有用。 ==== 初始实现 * 提供 `@Sealed` 标记注解或 AST 转换,允许定义允许的子代列表。此注解的使用将是一个孵化功能,可能会发生变化。显式使用最终可能会被劝退,取而代之的是鼓励使用关键字,例如 `sealed`。但是,可以保留注解,以便在任何语法更改之前在早期 JVM 或 Groovy 版本上提供此功能的支持。 * 禁止扩展 JDK17+ 密封类或带 `@Sealed` 注解的类。这同样适用于接口、匿名内部类和特质。 * 在可能隐式发生此类扩展的其他地方提供检查,例如:使用 `@Delegate`、使用类型强制转换等。 * 支持 `non-sealed` 或 `unsealed` 子层次结构。(参见 JEP-409) * 仅在基类和所有允许的子类在同一文件中时,自动推断允许的子类。(参见 JEP-409) * 在语法中引入 `sealed` 修饰符和 `permits` 子句。 * 默认情况下,在 JDK17+ 上运行时,密封类信息会添加到字节码中。我们将此类类称为“原生”密封类。 * 默认情况下,在早期 JDK 上运行时,会将注解添加到类中,以指示该类是密封的。此类类将由 Groovy 4+ 编译器识别,但不会由 Java 识别。 * `@SealedOptions` 注解具有 `mode` 注解属性,可以覆盖默认行为。 ==== 潜在扩展 以下潜在扩展可能都是理想的,但不是第一次实现的目标: * 要求密封层次结构中的所有类同时编译。 * 要求密封层次结构中的所有类属于同一 JPMS 模块。 * 如果 switch 用于密封层次结构且未穷尽地覆盖所有类型,则向静态编译器添加警告。 == 参考文献和有用链接 * https://openjdk.org/jeps/360[JEP 360: 密封类(预览版)] * https://openjdk.org/jeps/397[JEP 397: 密封类(第二预览版)] * https://openjdk.org/jeps/409[JEP 409: 密封类] * https://kotlinlang.org/docs/sealed-classes.html[Kotlin 中的密封类] * https://github.com/scala/improvement-proposals/pull/43[Scala 中的密封类型](已撤回) === 参考实现 https://github.com/apache/groovy/pull/1606 === JIRA 问题 * https://issues.apache.org/jira/browse/GROOVY-10148[GROOVY-10148: Groovy 不应允许类扩展密封 Java 类] == 更新历史 1 (2021-07-22) 初始草稿 + 2 (2021-11-06) 更新以与 4.0.0-beta-2 对齐

GEP-13