Data classes 是一种替代Java中传统POJOs的简洁方式,每当有人向Java开发者推广Kotlin是救世主的时候,data classes 一定是前三的理由之一。
别误解我,data classes 很棒, 但是从每个人谈论它们(也包括使用,我打赌)的样子看,许多人并不懂 data 关键词真正对一个类做了什么。所以,让我们搞清楚!
传统类(Regular classes)
这是一个非常简单的没有 data 关键词的数据模型类:
1 | class Person(val name: String, var age: Int) |
这个类实际上已经和我们叫做 POJO 的类是一样的了。在 Java 里,它有两个字段,合适的 getters 和 setters,然后还有一个有两个参数的构造器。
1 | public final class Person { |
数据修改器(The data modifier)
现在我们把这个类变成一个 data class
1 | data class Person(val name: String, var age: Int) |
所做的是给我们添加了一些额外生成的方法,从 Java 代码的角度看像下面这样(简化后的):
1 | public final class Person { |
前面三个方法具有自我解释性,它们只是 Any(或者 Object)类的方法的合理实现。
注意到生成的 equals 和 hashCode 方法始终并只使用主构造器中的属性。如果需要不一样的行为,你就得自己去实现这些方法。这可能是你想不使用 data class 的一个地方。
然而,优势是这些方法是在编译期生成的,意味着他们始终是最新的,能够用到主构造器中的每个属性。如果你在自己的代码里维护这些方法的话,没当你添加、删除或者改变一个属性的时候,都要自己去维护这些方法!
Data class 中其余的方法是 Kotlin 特有的,你应该永远都不要从 Java 代码中进行调用。
componentN 风格的方法是支持解构声明(destructuring declarations)的一种约定。在下面的例子中,它允许我们把类分解成多个变量:
1 | val natalie = Person("Natalie", 43) |
copy 方法允许我们创造一个我们类的新实例,新实例默认每个属性的值都保持一样:
1 | val nat = natalie.copy() // Person(name=Natalie, age=43) |
Data class的每个属性还有一个可选的参数(有默认值)。你能够通过使用命名参数挨个按照自己的期望去改变。
1 | val will = natalie.copy(name = "Will") // Person(name=Will, age=43) |
如你所见,任何没有被提供的参数都能在新的实例里保留默认值。
优点和缺点
所以,选择这个或者另一个的优点是什么?(缺点的列表本质上是相同的,只是反过来)
常规类的优点:
- 对许多使用场景来说足够了
- 生成更少的方法:在 Android 上仍然是一个需要关心的地方
- 在继承上没有任何限制:data classes 在继承上有一些痛点
- 可以有非属性的构造函数参数:data classes 要求所有的主构造器参数都是属性
Data classes 的优点:
- 合理地实现了 Any 的方法:使得调试、比较和在 Map 中当做 key 使用变得更容易
- 支持解构
- copy 方法:对不可变类尤其有用
- 真的、真的很流行
结论
Data classes 非常好,带来很多特性的功能。但是 Kotlin 的常规类似乎没有得到应有的关注度,它们比大多数人想象得更有用处!
所以下次你准备创建一个 data class 的时候,想想你是否真的需要它的功能,如果你只是想创建有几个属性的简单类的话。