kotlin doc 之 数据类和封装类

数据类(Data Class)

我们经常会频繁的创建保存数据的类。在这样的一个类中,一些标准的函数是可以从data中导出的。在kotlin中,这被称为data class。

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

这个编译器会自动从primary constructor的声明属性中得到下面成员:

  • equals()/hashCode 对
  • toString() 以格式“User(name = john, age = 42)”
  • 与属性声明顺序相关的 componetN()方法
  • copy()方法

为了确保data class 生成代码的一致性,必须要保证它满足一下特点:

  • primary construcotr 的参数个数必须大于0
  • primary constructor中的参数必须标明“val”或者“var”
  • data class 不能为抽象,open,sealed ,或者inner
  • 1.1之前,data class只能实现一个接口

另外,成员的生成遵循一下原则,考虑到成员的继承。
* 如果data class中显示实现了 equal(),hashCode()或者toString()时,这些方法将不会被生成,自定义实现的将被使用。
* 如果父类有componentN()方法,并且它是open 且返回值类型兼容,那么子类相应的函数将会重写父类。如果由于签名类型或者final导致父类方法不会重写,将会报出异常。
* 继承一个有copy方法的父类将被禁止(版本1.2过时,版本1.3禁止)
* 提供显式的componentN()/copy()将不被允许。

从1.1开始 data class 可以继承其它类。
在JVM中,如果一个类需要一个无参构造函数,默认值将被指明到相应属性。

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

类体中声明的属性

注意,编译器仅仅使用primary constructor中定义的参数自动生成方法。为了排除一些属性,将它声明在类体。

data class User(val name : String){
    var age : Int = 0
}

仅有name属性将被在 toString()、hashCode()、equals() 和copy()方法实现中。并且仅有一个名为component1()的componentN()方法。如下面案例,尽管两个User object 有不同的年龄,但是它们被认为是 euqals。

User user1 = User("android")
User user2 = User("android")
user1.age = 10
user2.age = 20

复制ing

我们经常遇到这样一种情况:我们需要复制一个对象,但是要改变其中的部分属性。这就是需要copy() 来满足需求。

上面类中的copy方法实现如下:

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

下面的调用满足上面的需求

val jack = User(name = "jack" , age = 1)
val oderJack = jack.copy(age = 2)

数据类和解构声明

详情查询解构声明

val jane = User("jane",35)
val (name,age) = jame

println("$name , $age years of age") //prints "Jane , 35 years of age"

标准的数据类

标准库提供了Pair和Triple。在大多是情况下命名一个数据类是一个更好的设计选择。因为它增加代码的可读性,通过提供有意义的名字

封装类(密封类)

密封类被用于限制类的继承,当一个值只有一种类型,不能有其它种类型。从某种意义上讲,它是枚举类型的扩展。一个枚举的值是被限制的,但是每一个枚举常量作为一个实例存在,而一个密封类的子类可以有多个实例保存状态。
为了声明一个密封类,你需要加sealed关键字。一个密封类可以有子类,但是这些子类必须和密封类房子同一个文件中。在1.1之前还必须嵌套。

sealed class Expr
data class Const(val number : Double) : Expr()
data class Sum(val e1 : Expr,val e2 : Expr):Expr()

object NotANumber : Expr()

上面的例子中,包含了版本1.1的一个新特性 允许data class 继承 其他class。

一个密封类可以抽象的,但是不能被直接实例化。

一个密封类不允许有非私有构造函数,它们的构造函数默认是私有的
注意继承密封类的子类的子类可以在任何地方进行声明。

使用密封类的优点在于引入了when表达式。

fun eval( expr :Expr) : Double = when(expr){
    is Const -> expr.number
    is Sum -> eval(expr.e1) + eval(expr.e2)
    NotANumber -> Double.NaN
}

猜你喜欢

转载自blog.csdn.net/dirksmaller/article/details/80675537