Kotlin学习系列之:数据类(data class)和密封类(sealed class)

一、数据类(data class)

    在介绍数据类之前,我们先来看看这样一段代码:

class Student(val name: String, var age: Int)

fun main(args: Array<String>) {

    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关键字,类的结构会发生变化,添加了很多方法,这就和扩展不一样了。我们来总结一下一共添加了哪些方法:

 

  • setter/getter
  • toString()
  • equals()
  • hashCode()
  • componentN()
  • copy()

前面三个方法都是kotlin.Any类中的定义的,在数据类中会被重写。接下来我们来介绍一下后面两个稍微陌生的方法:

 

  • 如何理解copy()方法:尽管主构造中声明的属性既可以被定义为var、val,但是最好的方式就是val,即为只读属性。声明为只读属性意味着一旦对象被创建后,它就会保持它的初始状态,特别是在多线程环境下不用担心它的值被其他线程而修改。假设把这种习惯或者说编码风格叫做一种约定,那么在这种背景下随之而来就会有一个问题:如果我们确实想修改只读属性的值,那么该怎么办?copy()方法就可以解决。
val copyStudent = student.copy(name = "xlh", age = 12)
  
println(copyStudent)

      打印:

    这样就会创建一个新的对象并且修改了它的只读属性然后返回。注意:
    i. 原来的Student对象的属性值并没有改变

    ii. 参数的传递问题:可以不传,表示不修改属性值;如果传递的参数不是按照声明的顺序,那么必须使用有名参数的形式来调用,其他的情况下任意。 

总结copy方法的作用:就是创建一个当前对象的一份拷贝,并且在copy的过程中可以选择性改变拷贝对象的属性值,而原来对象的属性值不会改变。注意这里是浅拷贝。

 

  • 理解componentN方法:能够保证数据类可以使用解构声明(destructuring declarations)。
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<String>){
    sayHello(Dog())
    sayHello(Cat())
}

2. 密封类从某种程度上可以说子类的枚举化,从类的层次上进行了限制。

3. 密封类子类的子类可以定义在任何地方,并不需要和密封类定义在同一个文件中。

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Kotlin 中,sealed class密封)是一种特殊的别,用于表示受限制的继承结构。它可以作为父限制其子的数量,使得编译器能够对可能的继承关系进行静态分析。 以下是 sealed class 的基本特性和用法: 1. sealed class 用关键字 `sealed` 进行声明,可以有多个子。 2. sealed class 是抽象的,不能直接实例化。 3. sealed class 的子必须在同一个文件中定义,不能在其他文件中定义。 4. 子可以是数据、普通或者对象声明。 5. sealed class 的子之间可以相互继承,但只能在同一个文件中进行。 使用 sealed class 的一个常见场景是用于表示有限的状态或型。通过限制子的数量,可以确保所有可能的情况都在编译时被考虑到,从而避免了在运行时出现意外的情况。 以下是一个使用 sealed class 表示表达式的例子: ```kotlin sealed class Expression { class Constant(val value: Int) : Expression() class Addition(val left: Expression, val right: Expression) : Expression() class Subtraction(val left: Expression, val right: Expression) : Expression() } ``` 在这个例子中,`Expression` 是一个 sealed class。它有三个子:`Constant`、`Addition` 和 `Subtraction`。这个 sealed class 用于表示一个数学表达式,它可以是一个常量、一个加法表达式或一个减法表达式。 使用 sealed class 可以有效地限制可能的表达式型,并且在处理表达式时,编译器能够静态检查确保所有情况都被考虑到。 总之,sealed classKotlin 中用于创建受限制的继承结构的一种机制,适用于表示有限状态或型的情况。它提供了一种安全、可控的方式来定义和处理子,并且允许编译器在编译时进行静态分析和检查。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值