Kotlin 笔记 3.5:数据类和密封类

数据类

在 Java 开发中,我们经常写一些数据类,字段就是对应数据库的字段,在 Kotlin 中,可以将这类类定义为 数据类

数据类使用 data 关键字标识,编译器会自动从主构造方法中根据所有声明的函数自动提取以下方法:

  • equals() / hashCode()
  • toString() 格式如 "User(name=John, age=42)"
  • componentN() functions 对应于属性,按声明顺序排列
  • copy() 函数

当然,如果这些函数我们自己定义了,或者从父类中继承了,就不会生成了。

创建数据类还必须满足以下条件:

  • 主构造函数至少包含一个参数(因为编译器就是根据主构造函数中的属性来生成方法的)
  • 主构造函数中的所有参数必须标记为 var 或者 val
  • 数据类不能是抽象的、open 的、密封的或者内部类

声明一个数据类:

fun main() {
    var person = Person("bv99xd4rd24gsd", "张三",30)
    println(person.toString())
}

data class Person(var id: String, var name: String, var age: Int) {

}
//输出结果为:
Person(id=bv99xd4rd24gsd, name=张三, age=30)

当我们需要编译器生成难道那些方法中,排除一些属性的时候,只需要将这个属性声明在类中就可以了,只要主函数中的参数相同,哪怕类中声明的函数不同,也视这两个对象是相同的:

fun main() {
    var person1 = Person("bv99xd4rd24gsd", "张三", 30)
    person1.school = "二中"
    var person2 = Person("bv99xd4rd24gsd", "张三", 30)
    person2.school = "三中"
    println("person1's hashcode = ${person1.hashCode()}")
    println("person2's hashcode = ${person2.hashCode()}")
    println(person1 == person2)
    println("person1 toString: ${person1.toString()}")
    println("person2 toString: ${person2.toString()}")
}

data class Person(var id: String, var name: String, var age: Int) {
    var school: String = "一中"
}
结果:
person1's hashcode = -578758523
person2's hashcode = -578758523
true
person1 toString: Person(id=bv99xd4rd24gsd, name=张三, age=30)
person2 toString: Person(id=bv99xd4rd24gsd, name=张三, age=30)

复制

有时候我们只需要对象中的一部分属性,这个时候就可以用到数据类的 copy() 了:

fun main() {
    var person = Person("bv99xd4rd24gsd", "张三", 30)
    println(person.toString())
    val newPerson = person.copy(id = "123111", name = "张三")
    println(newPerson.toString())
}

data class Person(var id: String, var name: String, var age: Int) {
    var school: String = "一中"
}
//执行结果:
Person(id=bv99xd4rd24gsd, name=张三, age=30)
Person(id=123111, name=张三, age=30)

密封类

密封类中 Kotlin 中一种特殊的类,它专门用来派生子类,使用 sealed 关键字来标识,密封类本身不能被实例化,只能实例化它的子类。

更特殊的是,密封类的子类只能和密封类在同一个文件中声明

使用密封类的好处就是,你可以清晰的知道这个类有多少个子类,当你使用 when 表达式的时候,可以写完所有分支,而不需要 else (官方这么说的,其实我并没觉得这个算得上是好处。。。鸡肋而已)