深入剖析 Java 新特性
范学雷
前 Oracle 首席软件工程师,Java SE 安全组成员,OpenJDK 评审成员
16539 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 23 讲
深入剖析 Java 新特性
15
15
1.0x
00:00/00:00
登录|注册

04 | 封闭类:怎么刹住失控的扩展性?

你好,我是范学雷。今天,我们聊一聊 Java 的封闭类。
封闭类这个特性,首先在 JDK 15 中以预览版的形式发布。在 JDK 16 中,改进的封闭类再次以预览版的形式发布。最后,封闭类在 JDK 17 正式发布。
那么,什么是封闭类呢?封闭类的英文,使用的词汇是"sealed classes"。从名字我们就可以感受到,封闭类首先是 Java 的类,然后它还是封闭的。
Java 的类,我们都知道什么意思。那么,“封闭”又是什么意思呢?字面的意思,就是把一些东西封存起来,里面的东西出不去,外面的东西也进不来,所以可查可数。
“封闭”、“可查可数”,这些词汇字面看起来好像很通俗,但是实际上并不容易理解。我们还是通过案例和代码,一步一步地来了解封闭类吧。

阅读案例

在面向对象的编程语言中,研究表示形状的类,是一个常用的教学案例。今天的评审案例,我们也从形状这个类开始,来研究一下怎么判断一个形状是不是正方形吧。
下面的这段代码,就是一个简单的、抽象的形状类的定义。这个抽象类的名字是 Shape。它有一个抽象方法 area(),用来计算形状的面积。它还有一个公开的属性 id,用来标识这个形状的对象。
package co.ivi.jus.sealed.former;
public abstract class Shape {
public final String id;
public Shape(String id) {
this.id = id;
}
public abstract double area();
}
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Java的封闭类是JDK 17中引入的新特性,通过使用sealed关键字来限制类的扩展性。本文通过讨论形状类的案例,展示了在面向对象编程中如何判断一个形状是否为正方形的问题。作者指出了无限制的扩展性带来的问题,并强调了限制可扩展性的重要性。在介绍了继承的安全问题后,作者提出了使用sealed关键字来限制类的扩展性,从而在可预测和可控的范围内实现安全和健壮的代码。这一新特性为接口设计和实现提供了新的可能性。文章通过案例分析和技术讨论,深入浅出地介绍了封闭类的概念和应用,为读者提供了对Java封闭类的全面了解。 文章通过讨论封闭类的声明和许可类的声明,详细介绍了如何使用sealed关键字来限制类的扩展性。作者通过案例回顾展示了封闭类如何帮助解决判断一个形状是否为正方形的问题,并提出了对封闭类的使用优先级和技术要点。最后,作者提出了思考题,引导读者深入思考封闭类的应用和可能的改动。 总的来说,本文通过深入的技术讨论和案例分析,全面介绍了Java封闭类的概念、原理和应用,为读者提供了对封闭类的全面了解和应用指导。读者可以通过本文快速了解封闭类的特点和使用方法,以及在实际编码中如何应用封闭类来限制类的扩展性,从而编写更加安全和健壮的代码。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入剖析 Java 新特性》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(16)

  • 最新
  • 精选
  • 许灵
    https://github.com/XueleiFan/java-up/pull/7

    作者回复: 代码干净利索!

    2021-11-22
    3
  • ABC
    我在openjdk的githubca仓库提交人员列表中看到老师了,https://github.com/openjdk/jdk/graphs/contributors,太强了,给老师点赞!

    作者回复: 哈哈,只是一部分工作。

    2021-11-23
    2
  • 雷霹雳的爸爸
    1. permits 得加上Rectangle,2. 要增加instance of Rectangle时候,长和宽是不是相等的逻辑,3. 正方形那段还是生效的,但是如果shape是Rect就不起作用了,所以还是应该认为1.0得isSquare不兼容新增加的许可类 假设我3判断的没错(确实还没去code...),那么我的问题也在这,因为岂不是这个例子整个逻辑链条都有问题了,这不就是一开始讲的不限制扩展性可能带来的问题么,进一步岂不是说明sealed classes并没法在强类型上带来太多有意义的约束...按着相对传统的——就是没有sealed语法得历史时间点那时得视角来看,应该是原来的isSquare(它是个静态方法)突破了Shape类型的约束(只定义了Area),如果想对未来潜在的变化有意义,那么应该让isSquare也作为Shape的一个抽象方法由子类型来复写,让Rect、Hex还是什么别的,根据自己类型特征得情况来确定isSquare得具体实现岂不是更合适...

    作者回复: 1)2)3)的判断都是对的。第3个问题,其实是我们讨论问题的重点。增加一个抽象方法当然是好办法,不过也有很多例子没有办法通过增加父类的方法来解决。封闭类需要和模式匹配一起使用,才能解决好问题3。模式匹配带来的变化,我们后面会讨论。

    2021-11-22
    2
    1
  • xianbin.yang
    让子类都实现一个isSquare的方法,判断自己是否正方形不行吗?

    作者回复: 可以,不过形状很多。

    2022-07-09
  • Minos
    表示它的类是长方形或者菱形的类。如果这个对象的每一个边的长度都是一样的,其实它就是一个正方形 菱形本身四条边都相等,只是夹角不是90度。夹角是90度的菱形是正方形;四条边相等的矩形是正方形;

    作者回复: 谢谢

    2022-07-05
  • 我要写代码!
    需要注意的是,由于许可类必须是封闭类的直接扩展,因此许可类不具备传递性。也就是说,上面的例子中,ColoredSquare 是 Square 的许可类,但不是 Shape 的许可类。 是不是 Square应该写成 Circle 也就是说,上面的例子中,ColoredSquare 是 Circle 的许可类,但不是 Shape 的许可类。

    作者回复: 该怎么理解ColoredSquare和Circle的关系(ColoredSquare extends Square)?

    2021-11-30
  • fatme
    如果一开始设计封闭类的时候,对许可子类的预估不足,造成后续要增加新的许可子类。这样就要修改 permits 代码,这不太方便,也违背开闭原则。permits 是否能支持通配符呢?这样同一个包的所有直接子类都是许可类,在一定程度上可以减少需要修改 permits 的情况。

    作者回复: 这是一个权衡和妥协,封闭类的好处,可能要到第10讲,我们才能理解清楚。

    2021-11-23
  • ABC
    1. permits需要增加新增的类;2和3都用实例模式匹配修改了一下.源码里面删掉了isSquare方法,考虑向下兼容可以在isSquare方法中调用新增的getInstanceName方法进行兼容. 用了返回实例类名的方式来返回指定类,以此判断,如果还有更好的办法,请老师指点. pr: https://github.com/XueleiFan/java-up/pull/8

    作者回复: 代码整体很好,只是我还有一个小的疑问,在PR里留言了。

    2021-11-22
    2
  • Jxin
    课后题 3.向前兼容,向后不兼容。向前因为没有长方形的场景,所以是兼容的;向后因为有了长方形的场景,但没有对应的 是否正方形的判断逻辑,所以不兼容。但1.0的实现本身就不合适,这个是否正方形的实现应该要跟着子类走,也就是以抽象方法要求子类必须做实现。 体会 类声明增加了约束性的修饰。既是语义上的增强,也是权限控制上更细粒度的升级。不过继承很少用了,感觉哪怕加了这个,大家也习惯于用组合。

    作者回复: 相对于继承,我更害怕组合的缺陷。 现实可能没有这么理想。 实际的情况往往是我们设计了1.0,用户实现了它们的逻辑,然后我们想在2.0里增加些什么(比如一个新方法),对用户来说已经太晚了(除非他知道并且愿意改代码)。

    2021-11-22
    2
  • 黄剑豪
    感觉这个例子举得不好,会让人不太理解使用场景,因为通常来说Shape本身不应该是个封闭场景。因为判断是否是正方形强行将其封闭,总觉得例子有点怪。

    作者回复: 嗯。 有没有什么好的例子的建议?选例子,可能是我花时间最多的地方,也是比较头疼的。

    2021-11-22
    2
收起评论
显示
设置
留言
16
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部