Sealed Classes的基本概念与目标

Sealed Classes(密封类)是Java 17中引入的一项正式特性,它允许类或接口的作者明确声明哪些其他类或接口可以扩展或实现它。其主要目标是赋予开发者更精确的继承控制权,通过在编译时限制类的子类型,来增强代码的安全性和可维护性。这与传统的final类(禁止任何继承)和普通非final类(允许无限制继承)形成了互补,提供了一个中间选项,使得在设计领域模型时,能够清晰地表达一个有限的、已知的层次结构。

Sealed Classes的语法规则

定义一个密封类主要涉及三个关键字的组合使用:sealedpermits和(在子类上使用的)finalsealednon-sealed

首先,使用sealed关键字修饰类或接口声明。紧接着,使用permits关键字列出被允许继承该密封类的所有子类。这些子类必须满足以下条件:它们必须与密封类位于同一模块中(如果使用了模块系统),或者位于同一个包中。子类自身也必须具有以下修饰符之一:1) final,终止进一步的继承;2) sealed,允许它自己成为另一个密封层次结构的根;3) non-sealed,向子类开放继承,但该开放是显式声明的,打破了密封性的传递。

Sealed Classes的代码示例

以下是一个简单的代码示例,展示了Sealed Classes的基本用法:

首先,定义一个密封类Shape,并允许CircleRectangle继承它。

public sealed class Shape permits Circle, Rectangle {    // ... 类的通用属性和方法}

然后,定义两个子类。Circle被声明为final,意味着它不能再有子类。

public final class Circle extends Shape {    public final double radius;    // ... Circle的特定实现}

Rectangle被声明为non-sealed,这意味着它允许被其他类自由继承。

public non-sealed class Rectangle extends Shape {    public final double length, width;    // ... Rectangle的特定实现}

在这个例子中,任何试图创建另一个未被permits子句授权的Shape子类(例如Triangle)的行为都会在编译时导致错误。

Sealed Classes与模式匹配的协同优势

Sealed Classes与Java中日益强大的模式匹配功能(如instanceof模式匹配和switch表达式)协同工作时,能极大地提升代码的健壮性和简洁性。由于编译器能够通过permits子句知晓所有可能的子类型,因此在使用模式匹配进行类型检查和转换时,可以实现穷尽性检查。

例如,在一个处理Shapeswitch表达式中,编译器可以验证是否已经覆盖了所有允许的子类(CircleRectangle),如果漏掉任何一个,编译器会发出警告或错误,从而避免潜在的运行时问题。

double area(Shape s) {    return switch (s) {        case Circle c -> Math.PI  c.radius  c.radius;        case Rectangle r -> r.length  r.width;        // 无需default子句,因为所有情况都已覆盖    };}

Sealed Classes的设计考量与最佳实践

在设计中使用Sealed Classes时,应仔细考量其意图。它最适合用于建模那些在领域逻辑中具有固定、已知变体的类型,例如数学表达式、AST节点、命令、事件类型或状态等。避免为了密封而密封,只有在确实需要限制层次结构且已知所有实现时才使用它。

最佳实践包括:1) 尽量保持密封层次结构的扁平和小巧,以发挥其最大优势;2) 优先考虑将子类定义为finalsealed以维持控制,谨慎使用non-sealed,因为它会引入不确定性;3) 与记录类(Records)结合使用,可以创建强大且简洁的数据载体层次结构。

总结

Java 17的Sealed Classes为语言带来了更细粒度的继承控制机制。通过sealedpermits关键字,开发者可以构建一个受限但明确的类层次结构,从而增强代码的封装性、安全性和可读性。当其与模式匹配等特性结合时,能够实现编译时的穷尽性检查,显著减少错误并提高开发效率。这一特性是Java迈向更强大类型系统和更优雅领域建模的重要一步。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐