一、枚举类

枚举类,用来界说常量调集的一种特殊类。运用 enum class 能够声明一个枚举类

1.1 创立枚举类

枚举常量用逗号分隔,每个枚举常量都是一个目标

enum class Color{
    RED,
    BULE,
    YELLOW
}
fun main() {
    //运用
    println(Color.RED)
}

【Kotlin 初学者】枚举类-密封类-数据类-继承

1.2 获取枚举相关信息

val name: String //获取枚举称号,,默许称号为枚举字符名
val ordinal: Int //获取枚举值在一切枚举数组中界说的次序,值从 0 开端
fun main() {
    //运用
    val blue = Color.BULE
    println(blue.name)
    println(blue.ordinal)
}

【Kotlin 初学者】枚举类-密封类-数据类-继承

1.3 枚举类增加特点

每一个枚举都是枚举类的实例,它们能够被初始化。

若需求指定值,则能够运用其结构函数。

//2.0版别
enum class Color2(val user: UserColor) {
    RED(UserColor("小红", 15)),
    BULE(UserColor("小蓝", 20)),
    YELLOW(UserColor("小黄", 30));
}
data class UserColor(val name: String, val age: Int)
fun main() {
    //2.0版别
    println(Color2.BULE.user)
}

【Kotlin 初学者】枚举类-密封类-数据类-继承

1.4 界说函数

enum class Color2(val user: UserColor) {
    ...
    RED(UserColor("小红", 15));
    fun addUser(adduser:UserColor)=
        UserColor("${adduser.name}-${user.name}"
            ,adduser.age+user.age)
}
fun main() {
    //枚举界说函数
    println(Color2.RED.addUser(UserColor("新", 40)))
}

【Kotlin 初学者】枚举类-密封类-数据类-继承

1.5 以泛型的办法拜访枚举类中的常量

自 Kotlin 1.1 起,能够运用 enumValues<T>()enumValueOf<T>()函数以泛型的办法拜访枚举类中的常量

@SinceKotlin("1.1")
public inline fun <reified T : Enum<T>> enumValues(): Array<T>
/**
 * Returns an enum entry with specified name.
 */
@SinceKotlin("1.1")
public inline fun <reified T : Enum<T>> enumValueOf(name: String): T
//运用
fun main() {
    println(enumValueOf<Color>("RED"))
    println(enumValues<Color2>().joinToString { it.user.toString() })
}

【Kotlin 初学者】枚举类-密封类-数据类-继承

1.6 代数数据类型(ADT)

能够用来表示一组子类型的闭集,枚举类便是一种简单的ADT。

运用枚举的要害好处在于运用 when 表达式的时分,假如能够 验证句子掩盖了一切状况,就不需求为该句子再增加一个 else 子句了。

enum class ColorADT {
    RED,
    BULE,
    YELLOW
}
class TakeColor(var colorADT: ColorADT) {
    fun selectColor(): String {
        return when (colorADT) {
            ColorADT.RED -> "赤色"
            ColorADT.BULE -> "蓝色"
            ColorADT.YELLOW -> "黄色"
             // 不再需求 `else` 子句,由于咱们现已掩盖了一切的状况
        }
    }
}
fun main() {
    println(TakeColor(ColorADT.BULE).selectColor())
}

【Kotlin 初学者】枚举类-密封类-数据类-继承

但是假如咱们想在返回是赤色的时分给一个提示。假如运用枚举类,那么还需求判断就有一些杂乱了。关于更杂乱的ADT,你能够运用Kotlin的密封类(sealed class)来实现更杂乱的界说。

二、密封类(sealed class)

  • 关于更杂乱的ADT,你能够运用Kotlin的密封类(sealed class)来实现更杂乱的界说,密封类能够用来界说一个相似于枚举类的ADT,但你能够更灵活地操控某个子类型。

  • 密封类能够有若干个子类,要承继密封类,这些子类有必要和它界说在同一个文件里。

  • sealed 要害字不能润饰 interface ,abstract class(会报 warning,但是不会出现编译过错)

2.1 创立密封类

sealed class ColorSealed{
    //以下都是密封类的子类
    //运用object用的是单例,由于下面两个子类没有特点,不论生成多少次都相同
    object Blue : ColorSealed()
    object Yellow : ColorSealed()
    //这个子类有特点,或许特点不同,所以要生成不同的目标
    class Red(val toast:String) : ColorSealed()
}

2.2 运用

运用密封类的要害好处在于运用 when 表达式的时分,假如能够 验证句子掩盖了一切状况,就不需求为该句子再增加一个 else 子句了。

class TakeColorSealed(var colorSealed: ColorSealed) {
    fun selectColor(): String {
        return when (colorSealed) {
            is ColorSealed.Blue -> "蓝色"
            is ColorSealed.Yellow -> "黄色"
            is ColorSealed.Red ->
                "赤色,${(this.colorSealed as ColorSealed.Red).toast}"
            //不再需求 else 子句,由于咱们现已掩盖了一切的状况
        }
    }
}
fun main() {
    println(TakeColorSealed(ColorSealed.Blue).selectColor())
    println("----------")
    println(TakeColorSealed(ColorSealed.Red("正告正告!!!")).selectColor())
}

这儿跟枚举类的运用不太相同。用到了 is 要害字

调用赤色提示的时分将当前的ColorSealed转化为ColorSealed.Red,由于编译时也不知道你传入的是Red还是其他的。

三、数据类

运用 data class 要害字创立一个只包括数据的类,这种类又称数据类。这个是Kotlin独有的,Java没有数据类。

编译器会自动的从主结构函数中根据一切声明的特点提取以下函数:

  • 生成 equals() 函数与 hasCode() 函数

  • 生成 toString() 函数,由类名(参数1 = 值1,参数2 = 值2,….) 构成

  • 由所界说的特点自动生成component1()、component2()、…、componentN()函数,其对应于特点的声明次序。

  • copy() 函数

数据类需求满意以下条件:

  • 主结构函数至少包括一个参数。

  • 一切的主结构函数的参数有必要标识为val或许var。

  • 数据类不能够声明为abstract,open,sealed或许inner。

  • 数据类不能承继其他类 (但是能够实现接口)。

data class DaTang (var name:String ,val age:Int)

在没有结构体的时分,大括号{}可省略。

3.1 创立数据类

data class DaTang (var name:String ,val age:Int){
    val emperor = "$name,是继隋朝之后的大一统华夏王朝,共历二十一帝,享国-$age-年。"
}
fun main() {
    println(DaTang("唐朝", 289))
}

【Kotlin 初学者】枚举类-密封类-数据类-继承

假如不运用 data class 要害字润饰,而运用class要害字润饰,如下:

【Kotlin 初学者】枚举类-密封类-数据类-继承

3.2 toString、equals和hashCode的个性化实现

【Kotlin 初学者】枚举类-密封类-数据类-继承

3.3 ==符号

data class DaTang (var name:String ,val age:Int){
    val emperor = "$name,是继隋朝之后的大一统华夏王朝,共历二十一帝,享国-$age-年。"
}
class DaTang2 (var name:String ,val age:Int){
    val emperor = "$name,是继隋朝之后的大一统华夏王朝,共历二十一帝,享国-$age-年。"
}
fun main() {
    println(DaTang("唐朝", 289))
    // "==“比较的是内容  equals(Any)。
    // 因未重写Any的equals函数,运用的是Any默许equals函数,所以比较的还是引证。
    // "===" 比较的是引证(类所占的内存区域)
    println(DaTang2("唐朝", 289) == DaTang2("唐朝", 289))
    //这儿运用的是data class,数据类重写了equals,比较的是数据类里面的数据。
    println(DaTang("唐朝", 289) == DaTang("唐朝", 289))
}

【Kotlin 初学者】枚举类-密封类-数据类-继承

3.4 copy() 函数

copy() 函数应该是相似Java中的clone() 办法

data class DaTang (var name:String ,val age:Int){
    val emperor = "$name,是继隋朝之后的大一统华夏王朝,共历二十一帝,享国-$age-年。"
}
fun main() {
    val datang = DaTang("唐朝", 289)
    println(datang)//DaTang(name=唐朝, age=289)
    //创立了了一个新的目标
    val diguo = datang.copy(age=500)
    println(diguo)//DaTang(name=唐朝, age=500)
}

【Kotlin 初学者】枚举类-密封类-数据类-继承

3.5 解构声明

数据类:由所界说的特点自动生成component1()、component2()、…、componentN()函数,其对应于特点的声明次序。

一般类:运用 operator 要害字界说component1()、component2()、…、componentN()函数

data class DataDaSong(var name:String ,var age:Int)
class DaSong(var name:String ,var age:Int){
    //解构语法:有必要从component1开端
    operator fun component1() = name
    operator fun component2() = age
}
fun main() {
    //运用一般类需求自己写component1、component2...componentN
    var (name,age) = DaSong("北宋",167)
    println("$name,是我国历史上继五代十国之后的朝代,传九位皇帝,享国-$age-年")
    //运用数据类支撑解构语法,自动生成operator fun component1
    var (dataname,dataage) = DataDaSong("北宋",167)
    println("数据类:$dataname,是我国历史上继五代十国之后的朝代,传九位皇帝,享国-$dataage-年")
}

【Kotlin 初学者】枚举类-密封类-数据类-继承

查看数据类反编译代码:

【Kotlin 初学者】枚举类-密封类-数据类-继承

四、 承继(extend)

Kotlin 答应一个类承继自另一个类

Kotlin 中一切类都承继自 Any 类

Any 类是一切类的超类,关于没有超类型声明的类是默许超类

Kotlin 类默许都是关闭的,要让某个类敞开承继,有必要运用 open 要害字润饰它。

留意:

在 Kotlin 中 Any 类是一切类的超类

在 Java 中 Object 类是一切类的超类

4.1 Any 超类

Any 默许提供了三个函数:

public open class Any {
    public open operator fun equals(other: Any?): Boolean
    public open fun hashCode(): Int
    public open fun toString(): String
}

从这儿发现 无论是类还是函数,都运用了 open 要害字润饰。

一起发现,这儿仅仅界说了函数,没有实现。为什么呢?由于Kotlin是跨渠道语言,能够在Android、macOS、Windows、JavaScript上运行,为了支撑跨渠道更友爱,在不同渠道有不同实现,所以在这儿并未展示。

4.2 承继类

/* 食物基类 */
open class Food{
    fun explain() = "Food explain"
}
class Apple :Food(){
}

不加 open 要害字润饰是不让承继滴,如下图:

【Kotlin 初学者】枚举类-密封类-数据类-继承

4.3 函数重写

在基类中,运用 fun 声明函数时,此函数默许为 final 润饰,不能被子类重写。

假如答应子类重写该函数,那么有必要运用 open 要害字润饰它, 子类重写函数运用 override 要害字。

/* 食物基类 */
open class Food{
    //函数有必要用 open 要害字润饰,子类才干掩盖
    open fun explain() = "Food explain"
}
/* 承继Food */
class Apple :Food(){
    //运用 override 要害字掩盖父类函数
    override fun explain() = "Apple explain "
}

在 Kotlin 中 override 是个要害字而不是注解。

运用

fun main() {
    //多态:父类类型的引证子类类型的目标
    val f: Food = Apple()
    println(f.explain())
}

【Kotlin 初学者】枚举类-密封类-数据类-继承

4.4 特点重写

/* 食物基类 */
open class Food {
    open val price = 100
    ...
}
/* 承继Food */
class Apple : Food() {
    override var price = 36
    ...
}
fun main() {
    //多态:父类类型的引证子类类型的目标
    val f: Food = Apple()
    println(f.explain())//Apple explain 36
}

【Kotlin 初学者】枚举类-密封类-数据类-继承

4.5 类型检测(is)

Kotlin的 is运算符 能够用来查看某个目标的类型。

    println(f is Food)//true
    println(f is Apple)//true
    println(f is File)//false

智能类型转化(as)

Kotlin的 as运算符 能够用对某个目标进行类型转化。

【Kotlin 初学者】枚举类-密封类-数据类-继承

智能安全转化操作符:as?

as?安全地转化成一种类型。 假如无法进行转化,则返回null,而不是抛出ClassCastException反常。

咱就在上面的实例基础上修正。

    var asTest :String? = ""
    //不安全的转化操作符 as
//    println(asTest as Int)//ClassCastException
    //安全的转化操作符 as?
    println(asTest as? Int)//null

【Kotlin 初学者】枚举类-密封类-数据类-继承