在Java 15中,引入了一项名为密封类(sealed classes)的预览特性,它为开发者提供了一种新的方式来控制类或接口的继承结构。这项特性允许开发者明确指定哪些类可以继承或实现某个特定的类或接口。这不仅增强了代码的可维护性,还有助于构建更安全、更可预测的类层次结构。
密封类是如何工作的?
在Java 15中,通过使用新的关键字sealed
和permits
来实现密封类。这些关键字允许开发者定义一个类或接口,并且明确指出哪些类可以继承它。
实例演示
考虑以下类层次结构示例:
public sealed class Account permits SavingsAccount, CheckingAccount {
}
public final class SavingsAccount extends Account {
}
public final class CheckingAccount extends Account {
}
在这个例子中,Account
类被定义为一个密封类,并且只允许SavingsAccount
和CheckingAccount
这两个类继承它。如果尝试通过一个未被允许的类来扩展Account
类,将会在编译时产生错误:
public class VirtualAccount extends Account {
}
// 编译错误:VirtualAccount.java:3:8 error: class is not allowed to extend sealed class: Account
final
类与密封类的区别
将类声明为final
是另一种形式的密封,它阻止所有类继承目标类。然而,密封类提供了一种比final
更灵活的密封形式,它通过permits
关键字提供了一种更声明式的方式来限制超类的使用,而不是通过访问修饰符。
允许的子类的限制
在上述例子中,允许的子类(SavingsAccount
和CheckingAccount
)必须具有以下修饰符之一,以描述它如何继续由其超类启动的密封:
final
:不能再被进一步扩展(在上述例子中,两个允许的子类都使用了final
修饰符)。sealed
:只能被其允许的子类扩展。这样我们可以进一步限制子类化。non-sealed
:可以被未知的子类扩展;密封类不能阻止其允许的子类这样做。
除了上述限制,允许的类必须与密封类在同一个模块中(如果密封类在命名模块中),或者在同一个包中(如果密封类在未命名模块中,如Account.java
示例所示)。有关模块的更多教程,可以查看这里。
为什么我们需要密封类?
在Java中,类层次结构允许我们通过继承来重用代码。然而,类层次结构的目的并不总是为了重用代码。有时,它的目的是模拟领域中存在的可能性,例如金融应用程序支持的账户类型(如上述例子所示)。当类层次结构以这种方式使用时,可以通过sealed
/permits
关键字实现限制子类的目的。
通过引入密封类,Java 15为开发者提供了一种新的方式来精确控制类继承,这有助于构建更加健壮和安全的应用程序。这项特性的引入,无疑是Java语言在面向对象编程领域迈出的重要一步。