您当前的位置: 首页 >  kotlin

Kevin-Dev

暂无认证

  • 0浏览

    0关注

    544博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

【Kotlin -- 知识点】数据类、密封类

Kevin-Dev 发布时间:2022-02-18 09:14:02 ,浏览量:0

文章目录
    • 一、数据类
      • 1. 关键字
      • 2. 数据类的特性
      • 3. 实例
    • 二、密封类
      • 1. 什么是受限的类继承结构
      • 2. 关键字
      • 3. 作用
      • 4. 使用密封类的好处

一、数据类 1. 关键字

声明数据类的关键字为:data

  • 声明格式

data class 类名(var param1 :数据类型,…){} 或者 data class 类名 可见性修饰符 constructor(var param1 : 数据类型 = 默认值,…)

说明:

  1. data为声明数据类的关键字,必须书写在class关键字之前。
  2. 在没有结构体的时候,大括号{}可省略。
  3. 构造函数中必须存在至少一个参数,并且必须使用val或var修饰。这一点在下面数据类特性中会详细讲解。
  4. 参数的默认值可有可无。

例:定义一个名为Person的数据类

data class Preson(var name : String,val sex : Int, var age : Int)
  • 约定俗成的规定 数据类也有其约定俗成的一些规定,这只是为增加代码的阅读性。即,当构造函数中的参过多时,为了代码的阅读性,一个参数的定义占据一行。

  • 编辑器为我们做的事情 当我们声明一个数据类时,编辑器自动为这个类做了一些事情,不然它怎么又比Java简洁呢。它会根据主构造函数中所定义的所有属性自动生成下列方法:

  • 生成equals()函数与hasCode()函数
  • 生成toString()函数,由类名(参数1 = 值1,参数2 = 值2,….)构成
  • 由所定义的属性自动生成component1()、component2()、…、componentN()函数,其对应于属性的声明顺序。
  • copy()函数。在下面会实例讲解它的作用。
2. 数据类的特性

数据类有着和Kotlin其他类不一样的特性。除了含有其他类的一些特性外,还有着其独特的特点。并且也是数据类必须满足的条件:

  • 主构造函数需要至少有一个参数
  • 主构造函数的所有参数需要标记为 val 或 var;
  • 数据类不能是抽象、开放、密封或者内部的;
  • 数据类是可以实现接口的,如(序列化接口),同时也是可以继承其他类的,如继承自一个密封类。
3. 实例

数据类通常需要重写 equals()、hashCode()、toString() 这几个方法:

  • equals:用来比较实例
  • hashCode:用来作为例如 HashMap 这种基于哈希容器的类
  • toString:用来为类生成按声明顺序排列的所有字段的字符串表达形式

在 Kotlin 中,只需要类中添加 data 关键字,以上这些必要的方法就会自动生成好,如下:

data class Person(val name: String,val age: Int)

fun main() {
    val person = Person("Kevin",18)
    println(person)

    val person2 = Person("Kevin",18)
    println(person == person2)

    val hashSet = hashSetOf()
    hashSet.add(person)
    println(hashSet.contains(person2))
}

运行结果:

Person(name=Kevin, age=18) true true

equals 和 hashCode 方法会将所有在主构造方法中声明的属性纳入考虑:

  • equals 方法会检测所有的属性的值是否相等
  • hashCode 方法会返回一个根据所有属性生成的哈希值
二、密封类

密封类是用来表示受限的类继承结构

1. 什么是受限的类继承结构
  • 所谓受限的类继承结构,即当类中的一个值只能是有限的几种类型,而不能是其他的任何类型。
  • 这种受限的类继承结构从某种意义上讲,它相当于是枚举类的扩展。但是,我们知道Kotlin的枚举类中的枚举常量是受限的,因为每一个枚举常量只能存在一个实例。
  • 但是其和枚举类不同的地方在于,密封类的一个子类可以有可包含状态的多个实例。
  • 也可以说成,密封类是包含了一组受限的类集合,因为里面的类都是继承自这个密封类的。但是其和其他继承类(open)的区别在,密封类可以不被此文件外被继承,有效保护代码。但是,其密封类的子类的扩展是是可以在程序中任何位置的,即可以不在同一文件下。
2. 关键字

定义密封类的关键字:sealed

声明格式

sealed class SealedExpr()

注意:密封类是不能被实例化的

3. 作用

用来表示受限的类继承结构。 例子:

sealed class SealedExpr{
data class Person(val num1 : Int, val num2 : Int) : SealedExpr()

object Add : SealedExpr()   // 单例模式
object Minus : SealedExpr() // 单例模式
}

// 其子类可以定在密封类外部,但是必须在同一文件中。`v1.1`之前只能定义在密封类内部
object NotANumber : SealedExpr() 

分析:即所定义的子类都必须继承于密封类,表示一组受限的类

  • 和普通继承类的区别
  • 普通的继承类使用open关键字定义,在项目中的类都可继承至该类。
  • 而密封类的子类必须是在密封类的内部或必须存在于密封类的同一文件。这一点就是上面提到的有效的代码保护。
  • 和枚举类的区别 枚举类的中的每一个枚举常量都只能存在一个实例。而密封类的子类可以存在多个实例。 例子:
val mPerson1 = SealedExpr.Person("name1",22)
println(mPerson1)

val mPerson2 = SealedExpr.Person("name2",23)
println(mPerson2)

println(mPerson1.hashCode())
println(mPerson2.hashCode())

输出结果:

Person(name=name1, age=22) Person(name=name2, age=23) -1052833328 -1052833296

4. 使用密封类的好处
  • 有效的保护代码
  • 在使用 when 表达式 的时候,如果能够验证语句覆盖了所有情况,就不需要为该语句再添加一个 else 子句了。

例子:

sealed class SealedExpr{    
	data class Person(val name : String, val age : Int) : SealedExpr()    
	object Add : SealedExpr()    
	companion object Minus : SealedExpr()
}

object NotANumber : SealedExpr()

fun eval(expr: SealedExpr) = when(expr){    
	is SealedExpr.Add -> println("is Add")    
	is SealedExpr.Minus -> println("is Minus")    
	is SealedExpr.Person -> println(SealedExpr.Person("Koltin",22))    
	NotANumber -> Double.NaN
}

输出结果:

is Minus

关注
打赏
1658837700
查看更多评论
立即登录/注册

微信扫码登录

0.2407s