一、对 class 加 data
编译器生成的方法(都基于主构造参数):
| 生成物 | 功能 | 如果手写会怎样 |
|---|---|---|
equals() |
逐字段比较 | 省掉 20 行模板代码,且字段变更时自动同步(手写版容易漏改) |
hashCode() |
逐字段 * 31 叠加 |
同上,且保证与 equals() 契约一致 |
toString() |
拼接 User(id=1, name=Tom) |
纯调试便利 |
copy() |
调用主构造的新实例 | 不可变数据建模的关键 |
componentN() |
按位置返回第 N 个属性的 getter | 支撑解构 val (a, b) = user |
它没有做的事:
❌ 没有基类、没有接口、没有注解注入------生成的就是普通方法
❌ 不影响内存布局,实例和普通类一样
❌ 不会自动实现 Serializable/Parcelable
❌ equals 比较只看主构造参数,函数体里声明的属性不参与:
二、对 object 加 data
普通 object 是饿汉单例,data 对它只改一个方法:toString()。
三、为什么要有这个关键字
去掉 data 你也能手写全部方法------它解决的是三个实际问题:
1、模板代码:5 个方法 × N 个字段,手写又长又易错
2、同步成本:加字段时自动更新 equals/hashCode/copy,手写版经常漏(尤其 copy 漏新参数)
3、语义表达:读代码的人一眼知道这是数据模型;IDE/库也能据此做处理(如 when 穷尽检查提示、序列化库的约定)
所以严格说:data = 编译期代码生成 + 设计意图标注,零运行时开销。