在 Kotlin 中,inline class(自 Kotlin 1.5 开始称为“value class”)允许以最小的开销创建类型封装。在编译时,此类会在幕后被其内部值(value)替换,以避免创建对象的开销。
限制和特点:
=== 不像平常那样工作)。示例:
@JvmInline value class UserId(val value: String) fun getUser(id: UserId) { println("Loading user with id: ${id.value}") } val id = UserId("XYZ") getUser(id) // 在幕后只是处理 String!
何时使用:
值类可以继承其他类或在接口/抽象类层次中使用吗?
答案: 不可以,值类不能继承其他类(不包括接口),不能对继承开放,不能包含 init 块和其他非静态字段。唯一可用的选项是实现接口。
示例:
interface Validatable { fun isValid(): Boolean } @JvmInline value class Email(val raw: String) : Validatable { override fun isValid() = raw.contains("@") }
故事
Android 应用在将值类添加到 Parcelable 参数后,启动时间骤然增加:发现不正确的 @Parcelize 与 value class 导致在每个序列化阶段进行装箱/拆箱,从而削弱了行内的优势。
故事
微服务开始积极使用值类用于 UserId 和 ProductId 以确保类型安全,但在许多地方,泛型函数要求反射,而反射无法与“封装”一起使用。单元测试意外失败,出现 ClassCastException。
故事
从 Java 迁移的代码开始用值类优化内部域类,但将其用作可空字段时导致意外的 null 指针异常,因为只有在外部值也为 null 时,值类才能为 null,这破坏了旧的不变性。