概述

  1. 封闭类JDK 17 正式发布

OOP

问题根源 - 无限制的扩展性

image-20241204185327701

限制可扩展性

  1. OOP 的最佳实践 - 把可扩展性限制在可控范围,而不是无限的扩展性
  2. 继承安全缺陷
    • 一个可扩展的类,子类父类可能会相互影响,导致不可预知的行为
    • 涉及敏感信息的类,增加可扩展性并非优先选项,尽量避免父类或者子类的影响
  3. 设计 API
    • 一个,如果没有真实的可扩展需求,使用 final 修饰符
    • 一个方法,子类如果没有重写的必要性,使用 final 修饰符
  4. 限制不可预测可扩展性,可以实现代码的安全性健壮性
  5. JDK 17 之前,限制可扩展性的两种方法 - 使用私有类或者 final 修饰符
    • 私有类不是公开接口,只能内部使用,而 final 修饰符彻底放弃可扩展性
    • 可扩展性 - 全开放 or 全封闭
  6. JDK 17 开始
    • 使用类修饰符 sealed 修饰的类是封闭类,使用类修饰符 sealed 修饰的接口是封闭接口
    • 封闭类和封闭接口 - 限制可以扩展或实现它们的其它类或接口
    • 可扩展性限制在可控范围

封闭类

  1. 被扩展的父类称为封闭类,扩展而来的子类称为许可类
  2. 使用类修饰符 sealed 声明封闭类
    • 在所有的 extendsimplements 语句之后,使用 permits 指定允许扩展封闭类子类
  3. permits 关键字指定的许可子类,必须和封闭类处于同一个 module 或者 package
    • 如果封闭类许可类同一个 module 中,它们可以处于不同的 package
  4. 如果允许许可子类封闭类同一个源码文件中,封闭类可以不使用 permits 语句
    • 编译器检索源码文件,在编译期为封闭类添加上许可子类
    • 最佳实践 - 总是使用 permits 语句 - 语义明确 + 可读性强

image-20241204194040271

许可类

约束

  1. 许可类必须和封闭类处于同一 module 或者 package - 在编译期间,封闭类可以访问它的许可类
  2. 许可类必须是封闭类直接扩展类 - 许可类不具备传递性
  3. 许可类必须声明是否继续保持封闭
    • 许可类可以声明为终极类(final),关闭扩展性
    • 许可类可以声明为封闭类(sealed),延续受限的扩展性
    • 许可类可以声明为解封类(non-sealed),支持不受限制的扩展性

Circle 是解封类,Square 是封闭类,ColoredSquare 是终极类
ColoredCircle 既不是封闭类,也不是许可类

Square 是 Shape 的许可类,ColoredSquare 是 Square 的许可类,但 ColoredSquare 并非 Shape 的许可类

image-20241204200048232

限定优先级

由高到低

  1. 使用私有类
  2. 使用 final 修饰符
  3. 使用 sealed 修饰符
  4. 不受限制的扩展性