目录

Kotlin系列(十七):面向对象之简洁好用的数据类

一、前言:

  • 数据类其实是Kotlin为了简化我们编程中不必要的一些操作而封装的一个类,如果你要追根究底的话,其原理很简单,就是kotlin在将其编译为class时,自动额外帮我们做了一些约定俗成,我们不想干的事情,释放我们的双手。
  • 对于Java程序员来说_JavaBean_这种类一定不陌生,其主要是用来定义数据类型。JavaBean的特点是一般对于每个字段我们都需要生成set和get方法,如果JavaBean中成员少还可以,当JavaBean的成员很多时,往往整个JavaBean类里都是自动生成的set和get方法,虽然是自动生成的,但还是影响了美观度和阅读性。
  • 对此,Kotlin为我们创造了数据类这个类型。
  • 以下学习参考自官方学习文档。

二、数据类

  • 我们经常创建一些只保存数据的类。 在这些类中,一些标准函数往往是从数据机械推导而来的。
  • 在 Kotlin 中,这叫做 数据类 并标记为 data

数据类的声明语法:

  • 声明一个数据类的完整格式:

      data class <类名><(主构造函数参数列表)>[: 继承类和实现接口][{/*类体*/}]
    
  • OK,现在我们可以声明一个简单的数据类:

      data class User(val name: String, val age: Int)
    
  • 编译器自动从主构造函数中声明的所有属性导出以下成员:

  • 1、equals()/hashCode() 对;
  • 2、toString() 格式是 "User(name=John, age=42)"
  • 3、componentN() 函数 按声明顺序对应于所有属性;
  • 4、copy() 函数(见下文)。
  • 以上便是Kotlin为了释放我们的双手为我们做的。其中componentN()这个函数很有趣,其实现的最终效果有点类似Python,js中用元组来接收数据。

数据类必须满足一定的要求

  • OK,为了确保生成的代码的一致性和有意义的行为,数据类必须满足以下要求:
  • 1、主构造函数需要至少有一个参数;
  • 2、主构造函数的所有参数需要标记为 valvar
  • 3、数据类不能是抽象、开放、密封或者内部的;
  • 4、(在1.1之前)数据类只能实现接口。

成员生成需要遵循的规则

  • 成员生成遵循关于成员继承的这些规则:
  • 1、如果在数据类体中有显式实现 equals()hashCode() 或者 toString(),或者这些函数在父类中有
  • 2、final*{: .keyword } 实现,那么不会生成这些函数,而会使用现有函数;
  • 3、如果超类型具有 open{: .keyword } 的 componentN() 函数并且返回兼容的类型, 那么会为数据类生成相应的函数,并覆盖超类的实现。如果超类型的这些函数由于签名不兼容或者是 final 而导致无法覆盖,那么会报错;
  • 4、不允许为 componentN() 以及 copy() 函数提供显式实现。
  • 自 1.1 起,数据类可以扩展其他类,如密封类,后面我们将会学习。

  • 在 JVM 中,如果生成的类需要含有一个无参的构造函数,则所有的属性必须指定默认值。

  • 示例代码如下:

      data class User(val name: String = "", val age: Int = 0)
    

三、copy复制

  • 前面我们说到,数据类会自动为我们创建copy函数。

  • 在很多情况下,我们需要复制一个对象改变它的一些属性,但其余部分保持不变。 copy() 函数就是为此而生成。对于上文的 User 类,其实现会类似下面这样:

      fun copy(name: String = this.name, age: Int = this.age) = User(name, age)     
    
  • 下面我们可以通过copy函数来使用原对象的一些属性值,但是修改一些新的值来创建新的对象:

      val jack = User(name = "Jack", age = 1)
      val olderJack = jack.copy(age = 2)
      println(jack)
      println(olderJack)
      println(jack===olderJack)
    
  • 结果输出为:

      User(name=Jack, age=1)
      User(name=Jack, age=2)
      false
    
  • 可以看到,其值发生了改变,对象也是不同的对象

四、数据类和解构声明

  • 为数据类生成的 Component 函数 使它们可在解构声明中使用:

      val jane = User("Jane", 35)
      val (name, age) = jane
      println("$name, $age years of age") // 输出 "Jane, 35 years of age"
    
  • 是不是感觉其很想python的元组的用法, 后面我们会单独分一章节来学习Component函数

五、总结

  • 本章节我们主要学习了Kotlin中的数据类,所以在使用Kotlin时,我们可以用数据类来替换Bean类,减少不必要的操作,提高生产率。