当前位置: 首页 > news >正文

Java密封类(Sealed Classes)增强详解

Java密封类(Sealed Classes)增强详解

Java 17引入了一个重要的新特性——密封类(Sealed Classes),这一特性旨在增强Java编程语言的能力,提供了一种机制来限制哪些类可以继承一个给定的类或者实现一个给定的接口。通过sealed和permits关键字,密封类不仅增强了类型安全性,还简化了代码结构,并在编译时进行了更精确的检查。以下是对Java密封类的深入解析。

一、密封类的定义与目的

密封类是通过sealed修饰符声明的类,它限制了哪些类可以继承它。同时,使用permits关键字来指定哪些子类是被允许的。这一特性的主要目的是防止类的无序扩展,确保类的继承体系在可控范围内,减少潜在的错误和异常逻辑。

在Java 17之前,一个类要么是可以被extends的,要么是final的,只有这两种选项。如果需要控制哪些类可以继承,通常只能通过改变类的访问级别,比如去掉类的public,将访问级别设为默认(包私有)。然而,这种方法并不能完全满足对类继承关系的细粒度控制需求。密封类的引入,正是为了解决这一问题。

二、密封类的语法与用法

密封类的语法如下:

public sealed class 父类名 permits 子类1, 子类2, ... {// 类成员
}public final class 子类1 extends 父类名 {// 子类1成员
}public sealed class 子类2 extends 父类名 permits 子类2_1, ... {// 子类2成员
}// 或者
public non-sealed class 子类3 extends 父类名 {// 子类3成员,子类3可以被任意类继承
}

在上面的语法中,父类被声明为sealed,并通过permits关键字指定了允许继承它的子类。子类可以是final的(禁止继承),也可以是sealed的(限制继承),还可以是non-sealed的(恢复开放继承)。

例如,假设我们有一个表示形状的类Shape,我们希望只有Circle、Rectangle和Square这三个类可以继承它,那么我们可以这样定义:

public sealed interface Shape permits Circle, Rectangle, Square {// Shape接口的成员
}public final class Circle implements Shape {// Circle类的成员
}public sealed class Rectangle implements Shape permits Square {// Rectangle类的成员
}public final class Square extends Rectangle {// Square类的成员
}

在这个例子中,Shape是一个密封接口,它只允许Circle、Rectangle和Square这三个类实现。同时,Rectangle也被声明为密封类,它只允许Square作为其子类。这样的设计使得类的继承体系更加清晰和可控。

三、密封类的优势与特点
  1. 增强类型安全性

密封类通过限制类的继承关系,可以减少类型转换的错误和潜在的运行时异常,提高程序的稳定性。例如,在上面的Shape例子中,由于我们限制了哪些类可以实现Shape接口,因此在编译时就可以检查到任何非法的继承关系,从而避免运行时错误。

  1. 简化代码结构

密封类可以减少需要显式声明的类和接口数量,简化代码结构。例如,在上面的例子中,我们不需要为Shape接口编写额外的防御性代码来防止未知的子类实现它,因为密封机制已经保证了只有指定的子类可以实现它。

  1. 提高代码的可读性和可维护性

在框架和库的设计中,使用密封类可以更好地控制类的继承体系,减少代码耦合性,提高代码的可读性和可维护性。例如,在图形库中,类的作者可能希望只有特定的类可以扩展Shape,因为库的大部分工作涉及以合适的方式处理每种形状。通过使用密封类,作者可以明确地指定哪些类可以扩展Shape,从而简化库的设计和维护。

  1. 支持模式匹配的未来发展方向

密封类还为模式的详尽分析提供了基础,支持模式匹配的未来发展方向。在Java 14中引入的模式匹配(Pattern Matching for instanceof)特性中,密封类可以作为其基础之一,使得编译器能够在编译时检查到更多的类型信息,从而提供更精确的错误检查和代码优化。

四、密封类的限制与注意事项
  1. 不支持匿名类和函数式接口的继承

由于密封类需要明确的继承关系,因此不支持匿名类和函数式接口的继承。这意味着,如果一个类被声明为密封类,那么它不能被用作匿名类的父类,也不能被函数式接口所实现。

  1. 子类必须位于同一模块或同一包中

在密封类的声明中,permits指定的子类必须位于同一模块中(如果超类在命名模块中)或在同一包中(如果超类在未命名模块中)。这一限制确保了密封类的继承关系在编译时是可控的,避免了跨模块或跨包的非法继承。

  1. 子类可以是final、sealed或non-sealed

在密封类的继承体系中,子类可以是final的(禁止继承),也可以是sealed的(限制继承),还可以是non-sealed的(恢复开放继承)。然而,需要注意的是,如果一个子类被声明为non-sealed,那么它就可以被任意类继承,这可能会破坏密封类所带来的类型安全性和代码简化性。因此,在使用non-sealed子类时需要谨慎考虑。

  1. 编译时检查

密封类提供了编译时的类型检查,确保不会出现意外的继承关系。然而,这也意味着在编写密封类时需要注意编译器的错误提示,并根据提示进行相应的修改。

五、密封类的应用场景与示例

密封类在Java中有着广泛的应用场景,特别是在框架和库的设计中。以下是一些常见的应用场景和示例:

  1. 状态机模式

在状态机模式中,系统状态的变化是有限的且有明确的定义。使用密封类可以确保只有预定义的状态类可以被创建,避免了意外的状态添加。例如,一个有限状态机(FSM)可以使用密封类来定义其状态集合,并通过permits关键字来指定哪些状态是合法的转换目标。

  1. 图形库

在图形库中,类的作者可能希望只有特定的类可以扩展某些基类或接口。例如,在上面的Shape例子中,作者可能希望只有Circle、Rectangle和Square这三个类可以扩展Shape接口。通过使用密封类,作者可以明确地指定哪些类可以扩展Shape接口,从而简化库的设计和维护。

  1. API设计

在API设计中,有时需要限制某些类的继承关系以避免潜在的错误和异常逻辑。例如,一个用于处理网络通信的API可能希望只有特定的类可以扩展其基类或实现其接口。通过使用密封类,API设计者可以明确地指定哪些类可以扩展或实现这些基类或接口,从而确保API的稳定性和安全性。

六、总结与展望

Java 17中的密封类是一个重要的语言特性,它提供了对类继承关系的更细粒度控制。通过限制哪些类可以继承一个给定的类或者实现一个给定的接口,密封类增强了类型安全性、简化了代码结构,并在编译时进行了更精确的检查。这对于框架和库的设计者来说尤其有用,因为它可以更好地控制类的继承体系、减少代码耦合性、提高代码的可读性和可维护性。

未来,随着Java语言的不断发展和完善,密封类可能会得到更多的应用和优化。例如,可能会引入更多的语法和特性来支持密封类的使用;可能会与其他语言特性(如模式匹配)进行更深入的集成;可能会提供更多的工具和库来帮助开发者更好地理解和使用密封类。总之,密封类作为Java 17的一个重要特性,将为Java语言的发展和应用带来更多的可能性和机遇。

相关文章:

Java密封类(Sealed Classes)增强详解

Java密封类(Sealed Classes)增强详解 Java 17引入了一个重要的新特性——密封类(Sealed Classes),这一特性旨在增强Java编程语言的能力,提供了一种机制来限制哪些类可以继承一个给定的类或者实现一个给定的…...

鸿蒙如何自动生成二维码?QRCode组件

QRCode 用于显示单个二维码的组件。 说明: 该组件从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 二维码组件的像素点数量与内容有关,当组件尺寸过小时,可能出现无法展示内容的情况&…...

【分布式知识】MapReduce详细介绍

文章目录 MapReduce概述1. MapReduce编程模型Map阶段Reduce阶段 2. Shuffle和Sort阶段3. MapReduce作业的执行流程4. MapReduce的优化和特性5. MapReduce的配置和调优 MapReduce局限性相关文献 MapReduce概述 MapReduce是一个分布式计算框架,它允许用户编写可以在大…...

JAVA八股

快速失败(fail-fast) 设计的目的是为了避免在遍历时对集合进行并发修改,从而引发潜在的不可预料的错误。 通过迭代器遍历集合时修改集合: 如果你使用Iterator遍历集合,然后直接使用集合的修改方法(如add(…...

关于武汉芯景科技有限公司的限流开关芯片XJ6288开发指南(兼容SY6288)

一、芯片引脚介绍 1.芯片引脚 二、系统结构图 三、功能描述 1.EN引脚控制IN和OUT引脚的通断 2.OCB引脚指示状态 3.过流自动断开...

指令:计算机的语言(五)

2.9 人机交互 ASCII与二进制 对应表略 字节转移指令 lbu:加载无符号字节,从内存中加载1个字节,放在寄存器最右边8位。 sb:存储字节指令,从寄存器的最右边取1个字节并将其写入内存。 复制1个字节顺序如下&#xf…...

C#笔记(1)

解决方案: 【1】组织项目:把项目放在放在一个解决方案中,统一开发,统一编译。 【2】管理项目:开发中的任何问题,在统一编译过程中,都能随时发现。也可以添加第三方的库文件。 命名空间: 命名空…...

SSDF攻击、防御与展望

摘要: 随着无线通信业务的不断发展,频域也越来越成为了一种珍贵的稀缺资源,与此同时,相应的无线电安全问题层出不穷,为无线通信造成了十分恶劣的影响,本文从深入理解认知无线电安全开始,对一些典…...

MedMamba代码解释及用于糖尿病视网膜病变分类

MedMamba原理和用于糖尿病视网膜病变检测尝试 1.MedMamba原理 MedMamba发表于2024.9.28,是构建在Vision Mamba基础之上,融合了卷积神经网的架构,结构如下图: 原理简述就是图片输入后按通道输入后切分为两部分,一部分走…...

单点登录的要点

单点登录(SSO)是一种身份验证服务,它允许用户使用一组凭据登录一次,然后在多个应用程序中访问其他应用程序而无需重新进行身份验证。这样,用户只需一次登录即可访问整个应用生态系统,提高了用户体验并简化了…...

linux线程 | 一点通你的互斥锁 | 同步与互斥

前言:本篇文章主要讲述linux线程的互斥的知识。 讲解流程为先讲解锁的工作原理, 再自己封装一下锁并且使用一下。 做完这些就要输出一堆理论性的东西, 但博主会总结两条结论!!最后就是讲一下死锁。 那么, 废…...

全栈开发小项目

用到的技术栈: nodejswebpackknockoutmongodbPM2rabbitmq 以下是一个综合指南,展示如何将 Node.js、Webpack、Knockout.js、MongoDB、PM2 和 RabbitMQ 集成到一个项目中。 我们将在这一项目中添加 RabbitMQ,用于处理消息队列。这对于任务分…...

批处理一键创建扫描仪桌面打开快捷方式图标 简单直接有效 扫描文档图片的应急策略

办公生活中,我们在安装完多功能一体机的打印驱动之后,找不到扫描文件的地方,如果驱动程序安装正确,我们可以用系统自带的扫描仪程序调用这种打印机或复印机的扫描程序即可,它在电脑系统中的位置一般是:C:\W…...

【服务器知识】Tomcat简单入门

文章目录 概述Apache Tomcat 介绍主要特性版本历史使用场景 核心架构Valve机制详细说明请求处理过程 Tomcat安装Windows系统下Tomcat的安装与配置:步骤1:安装JDK步骤2:下载Tomcat步骤3:解压Tomcat步骤4:配置环境变量&a…...

【前端】Matter:过滤与高级碰撞检测

在物理引擎中,控制物体的碰撞行为是物理模拟的核心之一。Matter.js 提供了强大的碰撞检测机制和碰撞过滤功能,让开发者可以控制哪些物体能够相互碰撞,如何处理复杂的碰撞情况。本文将详细介绍 碰撞过滤 (Collision Filtering) 与 高级碰撞检测…...

wps图标没有坐标轴标题怎么办?wps表格不能用enter下怎么办?

目录 wps图标没有坐标轴标题怎么办 一、在WPS PPT中添加坐标轴标题 二、在WPS Excel中添加坐标轴标题 wps表格不能用enter下怎么办 一、检查并修改设置 二、检查单元格保护状态 三、使用快捷键实现换行 wps图标没有坐标轴标题怎么办 一、在WPS PPT中添加坐标轴标题 插入…...

在ESP-IDF环境中如何进行多文件中的数据流转-FreeRTOS实时操作系统_流缓存区“xMessageBuffer”

一、建立三个源文件和对应的头文件 建立文件名,如图所示 图 1-1 二、包含相应的头文件 main.h 图 2-1 mess_send.h mess_rece.h和这个中类似,不明白的大家看我最后面的源码分享 图2-2 三、声明消息缓存区的句柄 大家注意,在main.c中定义的是全局变…...

ConcurrentLinkedQueue适合什么样的使用场景?

ConcurrentLinkedQueue 是 Java 中一种无界线程安全的队列,适合多线程环境中的高并发场景。以下是一些它特别适合的使用场景: 1. 高频读操作,低频写操作 ConcurrentLinkedQueue 对于实际应用中读操作相对频繁,写操作较少的场景非…...

C语言 | Leetcode C语言题解之第480题滑动窗口中位数

题目: 题解: struct Heap {int* heap;int heapSize;int realSize;bool (*cmp)(int, int); };void init(struct Heap* obj, int n, bool (*cmp)(int, int)) {obj->heap malloc(sizeof(int) * (n 1));obj->heapSize 0;obj->cmp cmp; }bool c…...

LabVIEW开发如何实现降维打击

在LabVIEW开发中实现“降维打击”可以理解为利用软件优势和高效工具来解决复杂的问题,将多维度、多层次的技术简化为容易操作和管理的单一维度,达到出其不意的效果。以下是几种关键策略: 1. 模块化设计与封装 将复杂系统分解为若干模块&…...

嵌入式快速原型开发:基于Sceptre平台与LPC2148的实战指南

1. 项目概述:Sceptre,一个被低估的嵌入式快速原型利器 在嵌入式开发的世界里,我们总是在寻找那个“刚刚好”的平台:它要足够强大,能跑复杂的算法;要足够小巧,能塞进各种外壳;要足够便…...

基于双T振荡器的正弦波LED调光电路设计与实践

1. 项目概述:用双T振荡器实现正弦波LED调光最近在捣鼓一些氛围灯项目,总感觉用单片机PWM做的呼吸灯效果有点“硬”,那种线性的明暗变化看久了难免审美疲劳。于是翻出以前模拟电路的老本行,琢磨着能不能用纯硬件的方式,…...

DLA功耗优化验证:tegrastats实战指南

重磅预告:本专栏将独家连载系列丛书《智能体视觉技术与应用》部分精华内容,该书是世界首套系统阐述“因式智能体”视觉理论与实践的专著,特邀美国 TypeOne 公司首席科学家、斯坦福大学博士 Bohan 担任技术顾问。Bohan先生师从美国三院院士、“…...

树莓派Zero离线语音交互实战:TTS与STT引擎部署与优化

1. 项目概述:为什么选择树莓派 Zero 来实现语音功能?如果你玩过 Arduino、ESP32 这类微控制器,也接触过树莓派 4B 这样的单板电脑,那你大概能理解那种“选择困难症”:微控制器实时性强、功耗低,但算力有限&…...

基于STM32WL与LoRaWAN的远程空气质量监测系统全栈开发实践

1. 项目概述:构建一个远程空气质量监测系统最近在做一个挺有意思的玩意儿:一个能自己找地方待着、靠太阳能供电,然后把周围空气数据悄无声息传回来的远程监测终端。核心想法很简单,就是想知道某个犄角旮旯,比如工厂周边…...

终极指南:5步掌握Cursor AI Pro完整功能免费解锁技巧

终极指南:5步掌握Cursor AI Pro完整功能免费解锁技巧 【免费下载链接】cursor-free-vip [Support 0.45](Multi Language 多语言)自动注册 Cursor Ai ,自动重置机器ID , 免费升级使用Pro 功能: Youve reached your tria…...

鼎讯AM-601光纤熔接机:交通通信建设与维护的可靠伙伴

在铁路、高速公路等交通基础设施的智能化建设中,稳定高效的光纤网络是指挥调度、安全监控等核心系统运行的生命线。鼎讯AM-601光纤熔接机,作为一款专为严苛环境设计的六马达便携式熔接设备,正成为保障这些关键通信链路畅通无阻的可靠选择。无…...

清华大学学位论文LaTeX模板:30分钟快速排版终极指南

清华大学学位论文LaTeX模板:30分钟快速排版终极指南 【免费下载链接】thuthesis LaTeX Thesis Template for Tsinghua University 项目地址: https://gitcode.com/gh_mirrors/th/thuthesis 还在为论文格式烦恼吗?清华大学官方LaTeX模板thuthesis让…...

Windows上直接安装APK文件:告别模拟器的轻量级安卓应用安装方案

Windows上直接安装APK文件:告别模拟器的轻量级安卓应用安装方案 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 还在为笨重的安卓模拟器烦恼吗?…...

压测不只是加并发:我们模拟真实用户行为后,发现了隐藏瓶颈

在性能测试领域,一个根深蒂固的误解是:压测就是使劲加线程数,看系统什么时候崩。很多团队用 JMeter 起 500 个并发,照着接口列表跑一圈,看到 TPS 平稳、响应时间没超过 300ms,就觉得万事大吉。可一旦上线&a…...