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

Java枚举类enum;记录类Record;密封类Sealed、permits

文章目录

  • 一、枚举类
    • 2. 在 Person 类中使用枚举
    • 3. 使用示例
  • 二、Java 14 记录类 (Record Classes)
    • 什么是记录类
    • 基本语法
    • 主要特性
    • 自定义行为
    • 使用示例
    • 限制
    • 适用场景
  • 三、Java 17 密封类型 (Sealed Classes)
    • 一、密封类型核心概念
      • 1. 设计目的
      • 2. 基本组成
      • 3. 三种继承约束
    • 二、规则
      • 1. 声明密封类
      • 2. 声明密封接口
      • 3. 子类要求
      • 4. 特殊规则
      • image-20250727155543950
    • 模式匹配与密封类
    • 实际示例
      • 基本密封类
      • 带密封子类的层次结构
    • 密封接口
    • 典型使用场景
      • 1. 代数数据类型(ADT)
      • 2. 状态机实现
      • 3. UI组件层次
    • 与模式匹配的完美结合
      • 1. switch 表达式
      • 2. instanceof 模式匹配
    • 编译时检查
    • 密封类的优点
    • 注意事项

一、枚举类

下面是一个简单的枚举类示例,展示了如何在Java中定义和使用枚举:

/*** 性别枚举类*/
public enum Gender {MALE("男"),FEMALE("女");private final String description;// 构造方法Gender(String description) {this.description = description;}// 获取描述信息public String getDescription() {return description;}// 重写toString方法@Overridepublic String toString() {return this.name() + "(" + description + ")";}
}

这个枚举类的特点包括:

  1. 基本定义:使用 enum 关键字定义枚举类 Gender
  2. 枚举值:包含两个枚举常量 MALEFEMALE
  3. 成员变量:每个枚举值都有一个对应的描述信息
  4. 构造方法:私有构造方法,用于初始化描述信息
  5. 公共方法:提供获取描述信息的方法和重写的 toString 方法

基于您提供的 [Person.java](file://C:\Users\win\IdeaProjects\untitled2\src\Person.java) 文件,我将展示如何使用枚举类。首先,让我创建一个枚举类,然后演示如何在 Person 类中使用它。

2. 在 Person 类中使用枚举

// Person.java
public class Person {private String name;private int age;private Gender gender;// 默认构造函数public Person() {}// 带参数的构造函数public Person(String name, int age, Gender gender) {this.name = name;this.age = age;this.gender = gender;}// getter 和 setter 方法public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Gender getGender() {return gender;}public void setGender(Gender gender) {this.gender = gender;}// toString 方法@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", gender=" + gender +'}';}
}

3. 使用示例

// 使用示例
public class Main {public static void main(String[] args) {// 创建 Person 对象并使用枚举Person person1 = new Person("张三", 25, Gender.MALE);Person person2 = new Person("李四", 30, Gender.FEMALE);System.out.println(person1);System.out.println(person2);// 获取枚举描述System.out.println("性别描述: " + Gender.MALE.getDescription());// 遍历所有枚举值System.out.println("所有性别选项:");for (Gender g : Gender.values()) {System.out.println(g + " - " + g.getDescription());}}
}

这样使用枚举的好处包括:

  1. 类型安全:编译时检查,避免无效值
  2. 代码可读性Gender.MALE 比数字或字符串更清晰
  3. 易于维护:枚举值集中管理
  4. 功能丰富:可以添加方法和属性

二、Java 14 记录类 (Record Classes)

Java 14 引入了记录类(Record Classes)作为预览特性,这是一种新的类声明形式,旨在简化不可变数据载体的创建。

什么是记录类

记录类是一种特殊的类,主要用于存储不可变数据。它自动提供以下功能:

  • 字段的自动声明(基于记录头中的组件)
  • 规范的构造函数
  • 自动生成的 getequals()hashCode()toString() 方法

基本语法

public record Point(int x, int y) {}

这个简单的声明等价于以下常规类:

public final class Point {private final int x;private final int y;public Point(int x, int y) {this.x = x;this.y = y;}public int x() { return x; }public int y() { return y; }@Overridepublic boolean equals(Object o) { ... }@Overridepublic int hashCode() { ... }@Overridepublic String toString() { ... }
}

主要特性

  1. 不可变性:记录类的所有字段都是 final 的
  2. 简洁语法:大大减少了样板代码
  3. 自动方法:自动生成访问器、equals、hashCode 和 toString
  4. 访问器方法:访问器方法与字段同名(如 x() 而不是 getX()
  5. final 类:记录类隐式是 final 的,不能被继承

自定义行为

虽然记录类自动生成许多方法,但你可以自定义它们:

public record Point(int x, int y) {// 紧凑构造函数(无需声明参数或赋值)public Point {if (x < 0 || y < 0) {throw new IllegalArgumentException("Coordinates must be non-negative");}}// 自定义方法public double distanceFromOrigin() {return Math.sqrt(x*x + y*y);}// 也可以覆盖自动生成的方法@Overridepublic String toString() {return String.format("Point[x=%d, y=%d]", x, y);}
}

使用示例

public class Main {public static void main(String[] args) {Point p1 = new Point(10, 20);Point p2 = new Point(10, 20);System.out.println(p1.x()); // 10System.out.println(p1.y()); // 20System.out.println(p1.equals(p2)); // trueSystem.out.println(p1); // Point[x=10, y=20]}
}

限制

  1. 记录类不能扩展其他类(隐含 final)
  2. 记录类的字段不能单独声明(必须在记录头中声明)
  3. 记录类不能是抽象的
  4. 记录类的组件(字段)是隐式 final 的

适用场景

记录类最适合用于:

  • DTO(数据传输对象)
  • 值对象
  • 简单的数据聚合
  • 方法返回多个值的场景

三、Java 17 密封类型 (Sealed Classes)

密封类是一种限制哪些其他类或接口可以继承或实现它的类或接口。这是对 Java 继承模型的增强,允许开发者明确控制类的层次结构。

一、密封类型核心概念

在传统 Java 中:

  • final 类:完全不能被继承
  • final 类:可以被任何类继承

密封类提供了中间选项:可以被特定的一些类继承,但不是所有类都能继承它。

1. 设计目的

  • 允许类/接口作者精确控制哪些类可以继承或实现它们
  • 解决传统继承模型中"要么完全开放,要么完全封闭"的限制
  • 为模式匹配提供更好的支持

2. 基本组成

  • 密封类/接口:使用 sealed 修饰的主类
  • permits 子句:明确指定允许的子类
  • 子类修饰符:必须为 final, sealednon-sealed

3. 三种继承约束

public sealed class Shape permits Circle, Square, Rectangle {}// 1. final: 不能再被继承
public final class Circle extends Shape {} // 2. sealed: 可以继续限制子类
public sealed class Rectangle extends Shape permits FilledRectangle {}// 3. non-sealed: 重新开放继承
public non-sealed class Square extends Shape {}

二、规则

1. 声明密封类

[访问修饰符] sealed class 类名 [extends 父类] [implements 接口...]permits 子类列表 {// 类体
}
  1. sealed 修饰符:标记类为密封类
  2. permits 子句:指定允许继承的子类
  3. 子类要求:所有允许的子类必须满足以下条件之一:
    • final:不能再被继承
    • sealed:可以进一步限制继承
    • non-sealed:开放继承(恢复传统 Java 行为)

2. 声明密封接口

[访问修饰符] sealed interface 接口名 permits 实现类列表 {// 接口体
}

3. 子类要求

  • 必须在同一模块(或未命名模块的同一包)中
  • 必须直接继承密封类
  • 必须显式声明为以下三种之一:
    • final:终止继承
    • sealed:继续密封
    • non-sealed:开放继承

4. 特殊规则

  • 如果子类与密封类在同一文件中,可省略 permits
  • 密封类和其子类应有相同的包访问权限
  • 记录类(record)可以作为密封类的子类

image-20250727155543950

模式匹配与密封类

密封类与 switch 表达式和模式匹配完美配合:

public double area(Shape shape) {return switch (shape) {case Circle c -> Math.PI * c.radius() * c.radius();case Square s -> s.side() * s.side();// 不需要default分支,因为Shape是密封的且所有子类都已处理};
}

实际示例

基本密封类

public sealed class Shape permits Circle, Square {public abstract double area();
}public final class Circle extends Shape {private final double radius;public Circle(double radius) { this.radius = radius; }@Overridepublic double area() {return Math.PI * radius * radius;}
}public final class Square extends Shape {private final double side;public Square(double side) { this.side = side; }@Overridepublic double area() {return side * side;}
}

带密封子类的层次结构

public sealed class Expressionpermits ConstantExpr, PlusExpr, TimesExpr, NegExpr {// ...
}public final class ConstantExpr extends Expression {private final int value;// ...
}public final class PlusExpr extends Expression {private final Expression left, right;// ...
}public sealed class TimesExpr extends Expressionpermits DivExpr {// ...
}public final class DivExpr extends TimesExpr {// ...
}public non-sealed class NegExpr extends Expression {// 可以被任意继承
}

密封接口

密封概念同样适用于接口:

public sealed interface Tree permits BinaryTree, Leaf {// ...
}public record Leaf(Object value) implements Tree {}public record BinaryTree(Tree left, Tree right) implements Tree {}

典型使用场景

1. 代数数据类型(ADT)

public sealed interface Exprpermits Constant, Add, Subtract, Multiply, Divide {double eval();
}public record Constant(double value) implements Expr {public double eval() { return value; }
}public record Add(Expr left, Expr right) implements Expr {public double eval() { return left.eval() + right.eval(); }
}// 其他运算类似...

2. 状态机实现

public sealed interface TrafficLightpermits Red, Yellow, Green, FlashingYellow {TrafficLight next();
}public final class Red implements TrafficLight {public TrafficLight next() { return new Green(); }
}public final class Green implements TrafficLight {public TrafficLight next() { return new Yellow(); }
}// 其他状态...

3. UI组件层次

public sealed class UIControlpermits Button, TextField, Slider, ComboBox {private String id;public abstract void render();
}public final class Button extends UIControl {public void render() { /* 按钮渲染逻辑 */ }
}public non-sealed class Slider extends UIControl {public void render() { /* 滑块渲染逻辑 */ }
}

与模式匹配的完美结合

1. switch 表达式

public String getShapeInfo(Shape shape) {return switch (shape) {case Circle c -> "圆形,半径: " + c.radius();case Square s -> "正方形,边长: " + s.side();case Rectangle r -> "矩形,面积: " + (r.length() * r.width());// 不需要default,编译器知道所有可能性};
}

2. instanceof 模式匹配

if (shape instanceof Circle c) {System.out.println("圆面积: " + c.area());
} else if (shape instanceof Square s) {System.out.println("正方形周长: " + s.perimeter());
}

编译时检查

Java 编译器会对密封类进行严格检查:

  1. 所有允许的子类必须可访问
  2. 每个允许的子类必须直接扩展密封类
  3. 每个允许的子类必须使用 finalsealednon-sealed 修饰
  4. permits 子句中的类必须存在

密封类的优点

  1. 增强代码可维护性:明确知道哪些类可以继承父类
  2. 改进模式匹配:编译器可以验证是否处理了所有情况
  3. 更好的领域建模:精确表示有限的子类型集合
  4. 提高安全性:防止未知子类的出现

注意事项

  1. 密封类及其子类通常应在同一模块中,或如果在不同模块中,则必须在同一包中
  2. 密封类的子类必须有规范的构造函数
  3. 反射 API 已更新以支持密封类检查

密封类是 Java 向更严格的类型系统和更好的模式匹配支持迈出的重要一步,特别适合需要精确控制类层次结构的领域建模场景。

http://www.lryc.cn/news/601496.html

相关文章:

  • Java面试宝典:MySQL执行原理一
  • 300.最长递增子序列,674. 最长连续递增序列,
  • Ubuntu服务器安装与运维手册——操作纯享版
  • 负载均衡Haproxy
  • [AI8051U入门第十一步]W5500-服务端
  • 嵌入式学习日志————对射式红外传感器计次
  • 【MySQL篇】:MySQL基础了解以及库和表的相关操作
  • DP之背包基础
  • SignalR 全解析:核心原理、适用场景与 Vue + .NET Core 实战
  • ASP.NET Core 高并发万字攻防战:架构设计、性能优化与生产实践
  • 一个MySQL的数据表最多能够存多少的数据?
  • 迷宫生成与路径搜索(A算法可视化)
  • 调用通义千问大模型实现流式对话
  • 用 Python 轻松实现时间序列预测:Darts N-BEATS
  • 安卓怎么做一个像QQ一样的开关切换控件
  • 墨者:通过手工解决SQL手工注入漏洞测试(MongoDB数据库)
  • 机器学习特征选择 explanation and illustration of ANOVA
  • net8.0一键创建支持(Redis)
  • 【机器学习】第七章 特征工程
  • 基于大模型的预训练、量化、微调等完整流程解析
  • CLAP文本-音频基础模型: LEARNING AUDIO CONCEPTS FROM NATURAL LANGUAGE SUPERVISION
  • PDF文件被加密限制怎么办?专业级解除方案分享
  • 51核和ARM核单片机OTA实战解析(一)
  • 一分钟部署一个导航网站
  • MCU 通用AT指令处理框架
  • PDF转图片实用指南:如何批量高效转换?
  • 创建的springboot工程java文件夹下还是文件夹而不是包
  • 内网服务器实现从公网穿透
  • 单片机ADC采集机理层面详细分析(二)
  • 零基础学习性能测试第五章:JVM性能分析与调优-多线程检测与瓶颈分析