一、数据类(data class)
在介绍数据类之前,我们先来看看这样一段代码:
class Student(val name: String, var age: Int)
fun main(args: Array) {
val student = Student("David", 12)
println(student)
}
此时会打印:
com.xlh.test.data.Student@49476842
大家都知道,这样直接打印student,会导致Student类的toString方法得到调用,最终打印到控制台的结果就是toString方法的返回结果。而Object类中的toString方法的实现(这里你可能产生疑问,Kotlin中的超级父类是Any类型,而不是Object类型,它俩的关系参看这篇博客):
所以就会出现前面的输出结果。
现在我们在类的声明前添加data关键字:
data class Student(val name: String, var age: Int)
其他不变,再看输出:
发生变化了,那就说明添加了data关键字后,Student类toString方法被重写了,并且形式为(属性名=属性值...),逗号分隔。实际上此时Student类就是一个数据类。
1. 如何定义数据类:
在类的声明前添加data关键字,即可将一个类定义成数据类。
2. 数据类需要满足的要求:
a) 主构造器至少有一个参数
b) 主构造器中的参数都需要使用var、val修饰
c) 数据类不能是abstract、open、sealed和inner的
3. 反编译,查看类的结构:
可以看到,一旦添加了data关键字,类的结构会发生变化,添加了很多方法,这就和扩展不一样了。我们来总结一下一共添加了哪些方法:
前面三个方法都是kotlin.Any类中的定义的,在数据类中会被重写。接下来我们来介绍一下后面两个稍微陌生的方法:
val copyStudent = student.copy(name = "xlh", age = 12)
println(copyStudent)
打印:
这样就会创建一个新的对象并且修改了它的只读属性然后返回。注意:
i. 原来的Student对象的属性值并没有改变
ii. 参数的传递问题:可以不传,表示不修改属性值;如果传递的参数不是按照声明的顺序,那么必须使用有名参数的形式来调用,其他的情况下任意。
总结copy方法的作用:就是创建一个当前对象的一份拷贝,并且在copy的过程中可以选择性改变拷贝对象的属性值,而原来对象的属性值不会改变。注意这里是浅拷贝。
val (name, age) = student
println("$name, $age")
此时就可以输出:
4. 关于data class最后再补充一点:
在第3点中列出的方法里,只针对定义在主构造函数中的属性,如果你定义了一个属性:
data class Student(val name: String, var age: Int) {
var address = "beijing"
}
这个address属性就不会被考虑。
二、密封类(sealed class)
1. 语法含义:密封类的子类要该密封类放置在同一个文件中。
2. 示例:
SealedTest.kt
sealed class Animal
class Dog : Animal() {
fun bark() {
println("wangwangwang")
}
}
class Cat : Animal() {
fun miao() {
println("miaomiaomiao")
}
}
fun sayHello(animal: Animal) {
when (animal) {
is Dog -> animal.bark() //Smart Cast
is Cat -> animal.miao()
//Don’t need else
}
}
fun main(args: Array){
sayHello(Dog())
sayHello(Cat())
}
2. 密封类从某种程度上可以说子类的枚举化,从类的层次上进行了限制。
3. 密封类子类的子类可以定义在任何地方,并不需要和密封类定义在同一个文件中。