数据类(Data Classes)

我们常常创建仅仅持有数据的类,类似Java中的POJO或JavaBean,其对象我们一般称为实体(entity),因此它对应我们常说的Entity类。在一般UI应用分层架构中,例如MVC,MVP,MVVM等,都含有一个模型(Model)层,实体类型就属于这一块,它是构建业务的基石。

为此Kotlin专门定义了data类型:

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

编译器会根据主构造函数中声明的属性自动生成如下成员:

  • equals()/hashCode()对
  • toString()方法,返回字符串形式为"User(name=John, age=42)"
  • componentN() 方法,其中N对应于属性声明的顺序
  • copy()函数

为了保持生成代码的一致性和行为的有效性,data类必须满足以下要求:

  • 主构造器需要至少一个参数
  • 所有主构造器参数需要声明为val或var
  • Data类型不能是abstruct、open、sealed或inner的

此外,对于成员继承,成员生成遵循以下规则:

  • 如果一个data类正文中明确实现了equals(),hashCode(),toString()方法,或者超类中有final修饰的实现,那么这些方法便不会生成,直接使用已有的实现。
  • 如果超类有open修饰的componentN()方法并且返回兼容的类型,那么对应的生成方法会重写超类的方法,否则会报错。
  • 显式地实现componentN()和copy()是不允许的

在JVM中,如果生成类需要有一个无参构造器,所有属性的默认值必须明确指定。

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

拷贝

copy()方法有什么用?有时我们需要拷贝一个对象,同时改变它的某些属性,并保持其它属性不变,使用copy()方法就可以了,其实现类似这样:

    fun copy(name: String = this.name, age: Int = this.age) = User(name, age) 

对象的属性值作为copy的默认参数值,我们可以传递希望改变的值,而保留其它值不变:

    val jack = User(name = "Jack", age = 2)
    val newJack = jack.copy(name = "New Java")

结构声明(Destructuring Declarations)

生成的component方法可以使它们使用解构声明中:

    val jane = User("Jane", 35) 
    val (name, age) = jane
    println("$name, $age years of age") // prints "Jane, 35 years of age"

标准库Data类

标准库提供了两个Data类:PairTriple

枚举类型(Enum Classes)

枚举类型最常见的基本使用是实现类型安全的枚举:

    enum class Direction {
        NORTH, SOUTH, WEST, EAST
    }

每个枚举常量都是一个对象,枚举常量使用逗号分开。

初始化

由于每个枚举常量都是一个实例,可以这样初始化:

    enum class Color(val rgb: Int) {
            RED(0xFF0000),
            GREEN(0x00FF00),
            BLUE(0x0000FF)
    }

密封类(Sealed Classes)