从spring HttpStatusCode源码聊聊jdk17新增的sealed关键字
背景
最近在开发的时候看到spring
中的HttpStatusCode
出现了一个以前低版本jdk
没用到的关键字sealed
所以打算来学习研究下这个新语法
何时引进
sealed
关键字在jdk15
和jdk16
都是作为预览特性出现
直到jdk17
才被正式引入
作用
sealed
关键字主要是用于通过permits
关键字明确指定允许继承的子类列表
我们先看看在没有sealed
关键字我们是如何限制类的继承
final关键字
如果一个类加上final
关键字,则完全禁止类被继承
public final class XiaoZou {}
现在类的访问权限
比如我们不将类设置为public
,使用默认的私有权限
package com.xiaozou;
class Animal {}
这样仅同包才能继承Animal
package com.xiaozou;
public class Dog extends Animal {}
缺点
我们可以看到通过上面的几种方式都没有办法只管切灵活的限制类的子类的实现。
比如我想要某个类,仅只能我自定义的几个类去实现。
我的这几个继承类可能是夸包,用上面的方式都不灵活。
那我们看看如何使用sealed
关键字进行实现
sealed关键字使用
继承限制
比如我这里有一个父类Car
我想要仅MiniCar
和BigCar
能继承
那么如何实现这个需求呢?
使用sealed
+ permits
关键字就很简单了
public sealed class Car permits MiniCar, BigCar { }
public final class MiniCar extends Car { }
public final class BigCar extends Car { }
sealed
关键字使用说明
-
如果使用
permits
限制了MiniCar
和BigCar
类的继承。则MiniCar
和BigCar
必须继承Car
,否则编译报错 -
MiniCar
和BigCar
必须声明为final
否则也会编译报错
实现的限制
不仅仅是对类的继承进行限制,也可以对接口的实现进行限制。
这里我们就不自己延时了,直接看spring
中HttpStatusCode
源码中的应用
spring中HttpStatusCode permits的应用
public sealed interface HttpStatusCode extends Serializable permits DefaultHttpStatusCode, HttpStatus {}
可以看到HttpStatusCode
接口限制了其实现类只能是DefaultHttpStatusCode
和HttpStatus
final class DefaultHttpStatusCode implements HttpStatusCode, Comparable<HttpStatusCode>, Serializable {}
public enum HttpStatus implements HttpStatusCode {}
DefaultHttpStatusCode
和HttpStatus
也确实实现了HttpStatusCode
接口
同时DefaultHttpStatusCode
也强制被声明成了final
HttpStatus
因为是枚举所以无需声明成final
如果我们自定义一个类去实现HttpStatusCode
接口就会发现编译报错
总结
jdk17
引入sealed
关键字主要有如下几个优势
-
精确控制继承(实现)关系: 通过
permits
明确列出允许继承(实现)的子类,避免意外的类扩展 -
增强代码可维护性: 明确的子类(实现)列表使代码结构更清晰,便于后续扩展或重构
-
模式匹配处理更安全
像上面Car
的例子我们可以直接使用模式匹配,安全处理所有可能的子类
public static void processCar(Car car) {
switch (car) {
case BigCar bigCar -> System.out.println("BigCar");
case MiniCar miniCar -> System.out.println("MiniCar");
case null -> System.out.println("Null car");
default -> System.out.println("Unknown car type");
}
}