Kotlin的值类(Value Class)是一种强大的类型安全工具,允许开发者创建语义明确的类型,并保持运行时零成本。

假设系统中存在用户的概念,用户拥有名字和电子邮箱地址。用户名和电子邮箱地址都是长度不超过120个字符的字符串。用户名不能是空白,不能是"null",也不能包含"@"。电子邮箱地址必须包含"@"。根据这些要求,我们可以得到一个简单的模型。

代码1  简单的User模型

data class User(val name: String, val email: String)

这个模型没有对值进行校验,客户端代码可能直接调用 user.name = "null" ,产生一条不满足业务约束的数据。为了避免这种情况,我们可以为用户名、电子邮箱分别建立模型。

代码2  复杂的User模型

data class User(val name: UserName, val email: Email)class UserName(val value: String) {init {require(!value.contains("@") && ... ) { "Invalid userName" }}
}class Email(val value: String) {init {require(value.contains("@")) { "Invalid email" }}
}

复杂模型可以保证业务逻辑不出错,但多了一个包装对象,产生运行时性能损耗。仔细观察UserName和Email两个类,都是把一个String对象和一些专属操作绑定起来,构成一个新类型。新类型可以表达语义,操作可以校验值。这两样都是我们需要的。有没有办法既能做到这两点,又不会产生额外的包装对象呢?答案就是值类。

代码3  值类:“基础”类型零成本抽象

@JvmInline
value class UserName(val value: String) {init {require(!value.contains("@") && ... ) { "Invalid userName" }}}

从语法上看,值类版本的UserName只比普通版本多了 @JvmInline 注释,并且将 class 换成了 value class ,其他方面并无差别。但在运行时,值类不会产生额外性能损耗,可以做到零成本抽象。

值类能做到运行时零成本的方法和C++模板或TypeScript类似,编译时在字节码级别进行内联。比如下面的值类

@JvmInline
value class Meter(val value: Double)fun calculate(m: Meter) = m.value * 2

编译后的字节码等价于

public static double calculate(double m) {return m * 2;
}

因此值类可以做到:

  • 没有额外对象分配
  • 没有虚方法表
  • 没有对象头开销
  • 方法调用转为静态分派

当然值类的使用也存在一些限制,包括:

  • 不能声明多个属性
  • 不能继承其他类(可以实现接口)
  • 不能在反射场景中使用
  • 需要特殊处理泛型场景

JVM泛型需要对象,因此在泛型中使用值类会引发装箱。

// 触发装箱
val list = listOf(UserId("123")) // 方案1:使用原始类型数组避免装箱(推荐)
val array = arrayOf(UserId("123"))// 方案2:通过inline class+类型投影减少装箱
val list = listOf<UserId>(UserId("123"))

值类的使用场景有:

  • 需要区分语义相似的原始类型时 (名字, 邮件等)
  • 需要为简单值添加领域行为时
  • 高频调用的基础类型包装
  • 要求极致性能的数值计算场景
  • 大型项目中的领域模型定义

需要避免值类的场景有:

  • 需要包装多个字段的复杂对象
  • 需要复杂继承关系的类型
  • 深度依赖反射的操作
  • 与某些Java框架深度集成的场景

值类的核心优势在于:

  1. 编译时类型安全
  2. 领域语义明确
  3. 零成本抽象
  4. 减少模型转换样板
  5. 增强代码可读性和可维护性
表1  值类和数据类对比
特性值类数据类(Data Class)
内存开销零(运行时内联)每个对象额外16-24字节对象头
适用场景单值包装多属性数据容器(如DTO)
自动生成方法仅基于包装值的方法equals()/hashCode()/copy()等
泛型处理可能触发装箱直接支持
表2  值类与装箱对比
特性值类装箱(以Integer为例)
设计目标类型安全的语义增强原始类型与对象类型的转换桥梁
内存开销0 (编译时内联)Integer: 16+字节对象头
类型系统创建真正的新类型int和Integer是相同值的不同表示
空值安全默认非空 (显式声明可空)int不能null, Integer可为null
集合性能等同于原始类型集合对象指针集合 (内存碎片化)
使用场景领域建模中的语义化类型泛型兼容和对象类型需求
表3  值类与值对象对比
维度值类DDD值对象 (Value Object)
范畴编程语言特性 (Kotlin特有)领域驱动设计(DDD)概念
核心目的零开销的类型安全包装表示没有唯一标识的领域概念
实现方式@JvmInline value class不可变类(通常用 data class)
身份标识无明确要求无唯一标识 (靠属性值区分)
相等性基于包装值 (可自定义)基于所有属性值
可变性默认可变 (但通常设计为不可变)严格不可变
典型应用ID包装、单位封装、类型别名金额、地址、日期范围、坐标点

值对象(Value Object)是领域驱动设计中不可变的概念片段,值类是Kotlin零开销的类型安全包装特性。二者主要是名称相似。如果当值对象只需封装单个值时,值类是最佳实现方式。

表4  值类和扩展方法
维度值类扩展方法
本质创建新类型扩展现有类型
类型系统编译时引入新类型 (运行时内联)不引入新类型
作用范围全局性的类型安全增强局部性的功能增强
主要目的解决类型安全问题解决功能扩展问题
使用方式创建新类型实例在现有类型实例上调用
性能影响零运行时开销极低开销(静态方法调用)
领域建模核心领域概念建模辅助功能实现

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/83877.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/83877.shtml
英文地址,请注明出处:http://en.pswp.cn/web/83877.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

arm64版BC-liunx-for-euler与X86_64版OpenEuler从源码安装git-lfs

1.arm64版BC-liunx-for-euler安装git-lfs 检查系统版本信息 uname -a Linux bms-42068966-004 5.10.0-136.49.0.127.10.oe2203.bclinux.aarch64 #1 SMP Tue Oct 10 14:09:09 CST 2023 aarch64 aarch64 aarch64 GNU/Linux 下载git-lfs构建脚本和源码 git clone https://gite…

2025国家卫健委减肥食谱PDF完整版(免费下载打印)

《成人肥胖食养指南&#xff08;2024年版&#xff09;》发布&#xff1a;科学减肥&#xff0c;从这里开始‌ 在这个追求健康与美的时代&#xff0c;减肥成为了许多人关注的热点话题。国家卫健委正式发布了《成人肥胖食养指南&#xff08;2024年版&#xff09;》&#xff0c;为我…

Android 手机如何实现本地视频音频提取?实战教程来了

我们经常会遇到这样的需求&#xff1a;比如看到一段喜欢的短视频&#xff0c;想把里面的背景音乐保存下来&#xff1b;或者需要从一段课程视频中提取语音内容用于学习。这时候&#xff0c;将手机视频转换成 MP3 音频就是一个非常实用的功能。 今天就来教大家如何使用一款简单好…

STM32项目---汽车氛围灯

一、蓝牙模块驱动 1、怎么使用蓝牙模块呢&#xff1f; 1&#xff1a;首先&#xff0c;先通过串口调试助手验证蓝牙模块是否正常使用。先连接好 2&#xff1a;打开串口调试软件配置好 3&#xff1a;发送测试指令&#xff1a;AT\r\n,返回OK&#xff0c;则说明连接正确&#xff…

python+uniapp微信小程序的共享雨伞租赁系统

目录 技术栈介绍具体实现截图系统设计研究方法&#xff1a;设计步骤设计流程核心代码部分展示研究方法详细视频演示试验方案论文大纲源码获取/详细视频演示 技术栈介绍 Django-SpringBoot-php-Node.js-flask 本课题的研究方法和研究步骤基本合理&#xff0c;难度适中&#xf…

一次生产故障引发的JVM垃圾回收器选型思考:彻底掌握垃圾回收原理及通用配置!

写在前面的话 前几天凌晨2点&#xff0c;我被一通电话惊醒——线上交易系统出现了严重的延迟问题&#xff0c;用户支付请求响应时间从平时的100ms飙升到了5秒&#xff0c;客服电话都被打爆了。 经过紧急排查&#xff0c;我们发现罪魁祸首竟然是JVM的垃圾回收器&#xff01;当…

学习日记-day30-6.15

完成目标&#xff1a; 知识点&#xff1a; 1.DDL和DML的补充 知识点 核心内容 重点 快速创建表 使用CREATE TABLE...AS SELECT语句基于现有表快速创建新表 结构和数据复制 vs 仅复制结构&#xff08;WHERE 12&#xff09; 数据删除操作 DELETE FROM逐条删除 vs TRUNCAT…

从检测到智能质控:IACheck如何成为TIC机构的AI中台?

一、TIC行业为何亟需AI质控&#xff1f; 过去十年&#xff0c;中国的TIC&#xff08;Testing, Inspection, Certification&#xff09;行业年均增长超过10%。无论是消费品、环境监测&#xff0c;还是工业制造、出口贸易&#xff0c;对“第三方检测报告”的依赖程度持续加深。 …

cka-1.32考题

1、HPA自动扩缩容 考题 &#xff08;考试的考题内容&#xff0c;只有下面方框里的内容&#xff09; 你必须连接到正确的主机。不这样做可能导致零分。 [candidatebase] $ ssh cka000050 Task 在 autoscale namespace 中创建一个名为 apache-server 的新 HorizontalPodAut…

DeepSeek 技术原理详解

引言 DeepSeek是一种基于Transformer架构的大型语言模型&#xff0c;它在自然语言处理领域展现出了卓越的性能。本文将深入探讨DeepSeek的技术原理&#xff0c;包括其架构设计、训练方法和优化策略&#xff0c;并结合代码实现进行详细讲解。 Transformer基础架构 DeepSeek基…

组件化 websocket

实时数据响应&#xff0c;组件化websocket减少代码冗余 组件定义 websocket.vue <template><div></div> </template><script>export default {data() {return {webSocket: null, // webSocket实例lockReconnect: false, // 重连锁&#xff0c;…

IBMS集成系统3D可视化数字孪生管理平台介绍、搭建、运维

IBMS集成系统3D可视化数字孪生管理平台介绍、搭建、运维 IBMS集成系统3D可视化数字孪生管理平台是一种先进的智能建筑管理系统&#xff0c;通过数字孪生技术和3D可视化界面&#xff0c;实现对建筑设施的全方位、智能化管理。该平台整合了物联网(IoT)、大数据、人工智能和三维建…

湖北理元理律师事务所:债务重组中的技术赋能与法律边界

一、当法律遇上算法&#xff1a;还款模型的进化 传统债务协商依赖律师经验&#xff0c;如今通过技术工具可实现&#xff1a; 输入&#xff1a;用户收入/债务/必需支出 输出&#xff1a; 1. 法定可减免金额&#xff08;基于LPR与历史判例库&#xff09;&#xff1b; 2.…

对抗串扰的第一武器

痕量分离;长度平行度;stackup&#xff1a;有没有一个脱颖而出&#xff1f; 我已经有一段时间没有看到关于串扰的文章了&#xff0c;所以我决定借此机会为那些可能对为什么精通串扰的 PCB 设计人员和硬件工程师使用各种设计规则来控制串扰感兴趣的 PCB 设计社区中的人简要介绍一…

FastAPI:(11)SQL数据库

FastAPI&#xff1a;(11)SQL数据库 由于CSDN无法展示「渐构」的「#d&#xff0c;#e&#xff0c;#t&#xff0c;#c&#xff0c;#v&#xff0c;#a」标签&#xff0c;推荐访问我个人网站进行阅读&#xff1a;Hkini 「渐构展示」如下&#xff1a; #c 概述 文章内容概括 #mermaid…

“智眸·家联“项目开发(一)

嵌入式开发调试知识点总结&#xff08;含操作流程&#xff09; 我们今天解决问题的过程&#xff0c;就像是侦探破案&#xff0c;从最表面的线索&#xff08;网络不通&#xff09;开始&#xff0c;一步步深入&#xff0c;最终找到了案件的核心&#xff08;硬件不匹配&#xff0…

展开说说Android之Retrofit详解_使用篇

Retrofit是由Square公司开发的类型安全HTTP客户端框架&#xff0c;借助动态代理在运行时生成接口实现类&#xff0c;将注解转化为OkHttp请求配置&#xff1b;节省成本通过转换器(Gson/Moshi)自动序列化JSON/XML&#xff0c;内部处理网络请求在主线程返回报文。Retrofit 直译是封…

复古美学浅绿色文艺风格Lr调色教程,手机滤镜PS+Lightroom预设下载!

调色介绍 复古美学浅绿色文艺风格 Lr 调色&#xff0c;是基于 Adobe Lightroom&#xff08;Lr&#xff09;软件&#xff0c;为摄影作品赋予特定艺术氛围的调色方式。通过合理设置软件中的各项参数与工具&#xff0c;把照片调整为以浅绿色为主调&#xff0c;融合复古元素与文艺气…

力扣网C语言编程题:缺失的第一个正数第三种解题方法

一. 简介 前面文章学习了对该题目的两种解题思路&#xff0c;文章如下&#xff1a; 力扣网C语言编程题&#xff1a;缺失的第一个正数-CSDN博客 但是前面的实现上在空间复杂度上没有满足要求。本文学习一种在空间复杂度上为 O(1)的思路。 二. 力扣网C语言编程题&#xff1a;缺…

PyTorch 实现 MNIST 手写数字识别

PyTorch 实现 MNIST 手写数字识别 MNIST 是一个经典的手写数字数据集&#xff0c;包含 60000 张训练图像和 10000 张测试图像。使用 PyTorch 实现 MNIST 分类通常包括数据加载、模型构建、训练和评估几个部分。 数据加载与预处理 使用 torchvision 加载 MNIST 数据集&#x…