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

85. Java Record 深入解析:构造函数、访问器、序列化与实际应用

文章目录

  • 85. Java Record 深入解析:构造函数、访问器、序列化与实际应用
    • **第一部分:构造函数(Constructor)**
      • **1. 记录的构造函数定义**
    • **第二部分:访问器(Accessor)**
      • **2.1 记录的默认访问器**
      • **2.2 自定义访问器**
    • **第三部分:记录的序列化(Serialization)**
    • **第四部分:实际应用案例(Use Case)**
      • **4.1 计算拥有最多城市的州**
        • **第一步:构建(Histogram)**
        • 1. 初始化空列表
        • 2. 流操作与分组统计
        • **第二步:找到最多城市的州**
        • **第三步:使用 `Record` 提升可读性**

85. Java Record 深入解析:构造函数、访问器、序列化与实际应用


第一部分:构造函数(Constructor)

1. 记录的构造函数定义

大家好,今天我们来深入学习 Java 的 Record(记录)类型。🚀

在 Java 中,Record是一种特殊的类,主要用于存储数据。每个Record都会自动生成构造函数、toString()equals()hashCode() 方法,使其非常适合用作数据载体。

我们可以为一个 Record 自定义构造函数,只要这个构造函数调用了该Record主构造函数(canonical constructor)。

来看看下面的例子:

public record State(String name, String capitalCity, List<String> cities) {// 紧凑构造函数(Compact Constructor)public State {cities = List.copyOf(cities); // 创建不可变列表,防止外部修改}// 无城市列表的构造函数public State(String name, String capitalCity) {this(name, capitalCity, List.of());}// 变长参数的构造函数public State(String name, String capitalCity, String... cities) {this(name, capitalCity, List.of(cities));}
}

🔹 这里的关键点

  • 紧凑构造函数(Compact Constructor)不需要显式列出参数,它的作用是在构造过程中做一些额外处理,比如这里的 List.copyOf(cities),确保 cities 不可变。
  • 重载构造函数:我们定义了两个额外的构造函数,一个用于不包含 cities 的情况,另一个允许使用 可变参数(varargs) 传递城市名称。
  • this() 调用:在 Java 中,构造函数的第一行必须调用同一个类的另一个构造函数或 super()

💡 示例应用场景: 假设你的程序中有一个 State 对象,它存储了某个州的名字、首府,以及一些城市信息。你希望:

  1. 确保城市列表不会在外部被修改。
  2. 允许用户创建不含城市列表State 对象。
  3. 允许用户直接传入多个城市名称,而不是自己创建 List<String>

这时,多个构造函数的设计就能满足不同的需求!


第二部分:访问器(Accessor)

2.1 记录的默认访问器

💡 大家还记得吗? 记录类型会自动生成访问器(accessor),即字段名相同的方法

比如:

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

这个 Point 记录会自动生成两个方法:

public int x() { return x; }
public int y() { return y; }

这样,我们可以直接调用 point.x()point.y() 获取值。

2.2 自定义访问器

有时候,默认的访问器不够用,比如 State 记录中,如果没有在构造函数中做防御性拷贝,我们可以在访问器中返回一个不可变副本:

public List<String> cities() {return List.copyOf(cities);
}

这样,每次访问 cities() 时都会返回一个不可变的列表,避免外部修改原始数据。


第三部分:记录的序列化(Serialization)

如果需要让 Record 支持序列化(Serialization),只需实现 Serializable 接口:

public record State(String name, String capitalCity, List<String> cities) implements Serializable {}

但是,要注意

  1. 不能使用 writeObject()readObject() 方法自定义序列化行为。
  2. 不能实现 Externalizable
  3. 反序列化时,始终会调用 主构造函数(Canonical Constructor),确保所有的校验逻辑都会被执行。

💡 示例场景: 如果你的应用程序需要在不同服务之间传输 State 对象,使用 Record 可以确保数据一致性,防止意外修改。


第四部分:实际应用案例(Use Case)

4.1 计算拥有最多城市的州

假设我们有一个 City 记录和 Zhou 记录:

public record City(String name, Zhou state) {}
public record Zhou(String name) {}

我们有一个 List<City>,需要找到拥有最多城市的州

第一步:构建(Histogram)
List<City> cities = List.of(new City("New York", new Zhou("NY")),new City("Los Angeles", new Zhou("CA")),new City("San Francisco", new Zhou("CA"))
);Map<Zhou, Long> numberOfCitiesPerState =cities.stream().collect(Collectors.groupingBy(City::state, Collectors.counting()));System.out.println(numberOfCitiesPerState);

这里,我们用 Collectors.groupingBy() 来计算每个州的城市数量

1. 初始化空列表
List<City> cities = List.of();
  • 作用:创建一个不可变的空列表,类型为 City
  • 特点:
    • Java 9+ 支持的工厂方法,语法简洁。
    • 列表一旦创建,无法添加或删除元素(不可变)。

2. 流操作与分组统计
Map<Zhou, Long> numberOfCitiesPerState =cities.stream().collect(Collectors.groupingBy(City::state, Collectors.counting()));
  • 流程分解
    1. cities.stream():将列表转换为流(Stream),以便进行链式操作。
    2. collect(Collectors.groupingBy(...)):使用收集器对流元素进行分组统计。
      • City::state:分组依据为 City 对象的 state 属性(即州)。
      • Collectors.counting():统计每个分组的元素数量。
  • 结果
    • 返回一个 Map<Zhou, Long>,键是州对象,值是该州的城市数量。
    • 示例:若有 3 个城市属于 “California” 州,则 Map 中会有键值对 California → 3L
第二步:找到最多城市的州
Map.Entry<State, Long> stateWithTheMostCities =numberOfCitiesPerState.entrySet().stream().max(Map.Entry.comparingByValue()).orElseThrow();

但这样写可读性不高,因为 Map.Entry<State, Long> 只是个键值对,缺乏语义信息

第三步:使用 Record 提升可读性

我们可以定义一个新的 Record,表示 “某个州及其城市数量”

record NumberOfCitiesPerState(Zhou state, long numberOfCities) {public NumberOfCitiesPerState(Map.Entry<State, Long> entry) {this(entry.getKey(), entry.getValue());}public static Comparator<NumberOfCitiesPerState> comparingByNumberOfCities() {return Comparator.comparing(NumberOfCitiesPerState::numberOfCities);}
}

然后,优化 max() 代码,使其更具可读性:

NumberOfCitiesPerState stateWithTheMostCities =numberOfCitiesPerState.entrySet().stream().map(NumberOfCitiesPerState::new).max(NumberOfCitiesPerState.comparingByNumberOfCities()).orElseThrow();

优势

  • 代码更加清晰,NumberOfCitiesPerState 让业务逻辑一目了然。
  • 避免直接操作 Map.Entry,提高可读性和可维护性。

总结

  1. 记录类(Record) 适用于不可变数据模型。
  2. 自定义构造函数 可增强安全性,如防御性拷贝。
  3. 访问器方法 可定制逻辑,增强封装。
  4. 序列化时,主构造函数始终被调用,保证一致性。
  5. 使用 Record 提高代码可读性和业务逻辑清晰度
http://www.xdnf.cn/news/604549.html

相关文章:

  • 关于千兆网络变压器的详细介绍
  • 【Flutter】多语言适配-波斯语RTL从右到左
  • 基于 Vue3 与 exceljs 实现自定义导出 Excel 模板
  • 如何在Mac 上使用Python Matplotlib
  • Redis 详解
  • G1人形机器人软硬件组成
  • vite学习笔记
  • Jenkins 2.426.2配置“构建历史的显示名称,加上包名等信息“
  • 计算机网络——每一层的用到的设备及其作用
  • Spring MVC-面试题(33)
  • Python asyncio库:基本概念与使用方法
  • voc怎么转yolo,如何分割数据集为验证集,怎样检测CUDA可用性 并使用yolov8训练安全帽数据集且构建基于yolov8深度学习的安全帽检测系统
  • React+MapBox GL JS引入URL服务地址实现自定义图标标记地点、区域绘制功能
  • vue 鼠标经过时显示/隐藏其他元素
  • FPGA高效验证工具Solidify 8.0:全面重构图形用户界面
  • 游戏引擎学习第306天:图结构排序的调试
  • QT-VStudio2107加载项目,报出“元素 <LanguageStandard>只有无效值“Default“”
  • ten-vad:低延迟、轻量化且高性能的流式语音活动检测系统
  • 2025年5月网工基础知识
  • rosbridge_suit、roslibpy 源码阅读与简单测试 —— 图片编解码与传输
  • 从 Docker 到 runC
  • 小说漫画管理系统
  • FRP技术概览
  • 黑马点评--短信登录实现
  • 针对面试-java集合篇
  • Alpha shapes算法边缘点进行排序(C++)
  • 「二叉搜索树·手撕暴走篇」:用C++《一路向北》狂写指针のの死亡轮盘!
  • 初识main函数
  • C/C++的OpenCV 进行图像梯度提取
  • [原创](计算机数学)(The Probability Lifesaver)(P14): 推导计算 In(1-u) 约等于 -u