Kotlin 小細(xì)節(jié)記錄(5)

83.Kotlin語(yǔ)言的繼承與重載的open關(guān)鍵字
84.Kotlin語(yǔ)言的類(lèi)型轉(zhuǎn)換
85.Kotlin語(yǔ)言的智能類(lèi)型轉(zhuǎn)換
86.Kotlin語(yǔ)言的Any超類(lèi)
87.Kotlin語(yǔ)言的對(duì)象聲明
88.Kotlin語(yǔ)言的對(duì)象表達(dá)式
89.Kotlin語(yǔ)言的伴生對(duì)象
90.Kotlin語(yǔ)言的嵌套類(lèi)
91.Kotlin語(yǔ)言的數(shù)據(jù)類(lèi)
92.Kotlin語(yǔ)言的copy函數(shù)
93.Kotlin語(yǔ)言的解構(gòu)聲明
94-Kotlin語(yǔ)言的運(yùn)算符重載
95-Kotlin語(yǔ)言的枚舉類(lèi)
96-Kotlin語(yǔ)言的枚舉類(lèi)定義函數(shù)
97-Kotlin語(yǔ)言的代數(shù)數(shù)據(jù)類(lèi)型
98-Kotlin語(yǔ)言的密封類(lèi)
99-數(shù)據(jù)類(lèi)使用條件

open 聲明class, is 和 as 關(guān)鍵字 作為檢查和轉(zhuǎn)換操作

kotlin 默認(rèn)創(chuàng)建一個(gè)Class情況的class是底層:public final class 拒絕繼承
如果想要可以后續(xù)繼承使用,需要在前面添加open 關(guān)鍵字

open class Parent(var name:String){
   fun show() = println("$name")
}


class Children(var childName:String):Parent(childName){
    fun show2() {
        println("parent:$name,child:$childName")
    }
}

fun main() {
    val p:Parent = Children("zcwfeng")
    println(p.name)
    val c = Children("david")
    if(c is Parent){
        val c2:Parent = c as Parent
        println(c2.show())
    }
}

is 和 as 關(guān)鍵字

安全非空操作

val x: String? = y as? String

Kotlin 在編譯時(shí)確保涉及泛型的操作的類(lèi)型安全,而在運(yùn)行時(shí),泛型類(lèi)型的實(shí)例不保存有關(guān)其實(shí)際類(lèi)型參數(shù)的信息。
List<Foo> 被刪除為 List<*>。 通常,無(wú)法在運(yùn)行時(shí)檢查實(shí)例是否屬于具有某些類(lèi)型參數(shù)的泛型類(lèi)型。
因此,編譯器禁止由于類(lèi)型擦除而無(wú)法在運(yùn)行時(shí)執(zhí)行的 is-check,例如 ints is List<Int> 或 list is T(類(lèi)型參數(shù))。 可以根據(jù)星形投影類(lèi)型檢查實(shí)例:【Any?】
koltlin 類(lèi)型推斷,進(jìn)行了只能轉(zhuǎn)換 【handleStrings】

if (something is List<*>) {
    something.forEach { println(it) } // The items are typed as `Any?`
}

val something = listOf("a","b")
    if(something is List<*>){
        println(something)
    }


fun handleStrings(list: List<String>) {
        if (list is ArrayList) {
            // `list` is smart-cast to `ArrayList<String>`
        }
    }

Reified 需要和inline 內(nèi)聯(lián)函數(shù)一起用

上面說(shuō)到open,和類(lèi)型轉(zhuǎn)換提到了泛型轉(zhuǎn)換

【 Reified 允許您在使用泛型來(lái)進(jìn)行編程的同時(shí),還能夠在運(yùn)行時(shí)獲取到泛型所代表的類(lèi)型信息,這在之前是無(wú)法做到的。當(dāng)您需要在內(nèi)聯(lián)函數(shù)中使用到類(lèi)型信息,或者需要重載泛型返回值時(shí),您可以使用 reified。使用 reified 不會(huì)帶來(lái)任何性能上的損失,但是如果被內(nèi)聯(lián)的函數(shù)過(guò)于復(fù)雜則,還是可能會(huì)導(dǎo)致性能問(wèn)題。因?yàn)?reified 必須使用內(nèi)聯(lián)函數(shù),所以要保證內(nèi)聯(lián)函數(shù)的簡(jiǎn)短,并且遵循使用內(nèi)聯(lián)函數(shù)的最佳實(shí)踐,以免讓性能受到損失?!?/p>

inline fun <reified A, reified B> Pair<*, *>.asPairOf(): Pair<A, B>? {
    if (first !is A || second !is B) return null
    return first as A to second as B
}


    val somePair: Pair<Any?, Any?> = "items" to listOf(1, 2, 3)
    val stringToSomething = somePair.asPairOf<String, Any>()
    val stringToInt = somePair.asPairOf<String, Int>()
    val stringToList = somePair.asPairOf<String, List<*>>()
    val stringToStringList = somePair.asPairOf<String, List<String>>()
    println("somePair -> ${somePair}")
    println("stringToSomething -> ${stringToSomething}")
    println("stringToInt -> ${stringToInt}")
    println("stringToList -> ${stringToList}")
    println("stringToStringList -> ${stringToStringList}")

Kt 所有類(lèi)都隱含繼承了Any(),Any類(lèi)在Kt中之制定了標(biāo)準(zhǔn),具體實(shí)現(xiàn)在各個(gè)平臺(tái)實(shí)現(xiàn)好了

單利實(shí)現(xiàn)
object class

object Test1 {
    init {
        println("kt init")
    }

    fun show() = println("ia am show Object class")
}

fun main() {
    println(Test1)
    println(Test1)
    println(Test1)

    println(Test1.show())

}

原理可以借助編譯器 中kt的反編譯工具查看。init----》static代碼塊,show 實(shí)現(xiàn)final 實(shí)現(xiàn),static 中給public static final Test1 INSTANCE 初始化

接口interface聲明調(diào)用,Kotlin只有一種方式object:接口實(shí)現(xiàn)。 java 有兩種方式

open class Test2 {
    open fun add(info:String) = println("kt add:$info")
}

class TestImpl:Test2(){
    override fun add(info: String) {
//        super.add(info)
        println("kt 具名實(shí)現(xiàn) add:$info")
    }

}

interface RunnableKt{
    fun runKt()
}

fun main() {
    val p = object : Test2(){
        override fun add(info: String) {
//            super.add(info)
            println("kt 匿名 add:$info")
        }
    }
    p.add("匿名實(shí)現(xiàn)")
    val pImpl = TestImpl()
    pImpl.add("張三")
    //Java interface 方式
    val p2 = object:Runnable{
        override fun run() {
            println("Java interface")
        }
    }
    val p3 = Runnable { println("Java interface2") }
    p2.run()
    p3.run()

    //Kt Interface 只有一種
    object:RunnableKt{
        override fun runKt() {
            println("Kt interface")
        }
    }.runKt()

}

伴生生對(duì)象,這個(gè)點(diǎn)很簡(jiǎn)單,Companion看反編譯代碼

class Test3 {
    companion object{
        val info = "demo"
        fun show() = println("compaion $info")
    }
}

fun main() {
    println(Test3.info)
    println(Test3.show())

    //companion 只有一次初始化
    Test3()
    Test3()
    Test3()
}

companion 底層實(shí)際,static final class的方式

內(nèi)部類(lèi)需要inner修飾,嵌套類(lèi)

class Test4(body:String) {
    val bodyInfo = body

    inner class Hand{
        fun work() = println("Hand is work with: $bodyInfo")

        inner class LeftHand { // 左手
            fun run() = println("左手訪問(wèn)身體信息:$bodyInfo")
        }

        inner class RightHand { // 右手
            fun run() = println("右手訪問(wèn)身體信息:$bodyInfo")
        }
    }

    inner class Heart{
        fun work() = println("Hand is work with: $bodyInfo")
    }

    fun show(){
        Hand().work()
    }
}

class Outer{
    val outString = "aaa"
    fun out(){
        Nested().nest()

    }
    class Nested{
        fun nest(){
            println("nest class")
//            Outer().out()
//            out()
//            println(outString)
        }
    }
}

fun main() {
// 內(nèi)部類(lèi):
    Test4("isOK").Hand().LeftHand().run()
    Test4("isOK").Hand().RightHand().run()

    // 嵌套類(lèi):
    Outer.Nested().nest()
}

嵌套類(lèi)特點(diǎn):外部的類(lèi) 能訪問(wèn) 內(nèi)部的嵌套類(lèi),內(nèi)部的類(lèi) 不能訪問(wèn) 外部類(lèi)的成員
內(nèi)部類(lèi)的特點(diǎn): 內(nèi)部的類(lèi) 能訪問(wèn) 外部的類(lèi),外部的類(lèi) 能訪問(wèn) 內(nèi)部的類(lèi)

data class 數(shù)據(jù)類(lèi)和普通類(lèi)
data class 特點(diǎn):

  1. 內(nèi)部進(jìn)行了component 函數(shù)對(duì)字段進(jìn)行解構(gòu)
  2. toString復(fù)寫(xiě)
  3. copy 克隆函數(shù)
  4. equals 重寫(xiě)

class Normal(var code:Int,var msg:String,var data:String)
data class DataNormal(var code:Int,var msg:String,var data:String)

fun main() {
    println(Normal(200,"isOk","body"))
    println(DataNormal(200,"isOk","body"))

    println(Normal(200,"isOk","body") == Normal(200,"isOk","body"))//false
    println(DataNormal(200,"isOk","body") == DataNormal(200,"isOk","body"))//true

}

data 的copy,只關(guān)心主構(gòu)造,不管次構(gòu)造

data class DataPerson(var name:String,var age:Int){
    var corinfo = ""
    init {
        println("主構(gòu)造被調(diào)用")
    }
    constructor(name:String):this(name,12){
        println("此構(gòu)造constructer構(gòu)造被調(diào)用")
        corinfo = "增加核心內(nèi)容"

    }

    override fun toString(): String {
        return "toString name:$name, age:$age, coreInfo:$corinfo"
    }
}

調(diào)用:
   val p1 = DataPerson("zhangsan")
    val p2 = p1.copy("zcwfeng",100)
    println(p1)
    println(p2)
--------
主構(gòu)造被調(diào)用
此構(gòu)造constructer構(gòu)造被調(diào)用
主構(gòu)造被調(diào)用
toString name:zhangsan, age:12, coreInfo:增加核心內(nèi)容
toString name:zcwfeng, age:100, coreInfo:

data class 解構(gòu)和普通class結(jié)構(gòu)對(duì)比

class Student(var name:String,var age:Int){
     operator fun component1():String = name
     operator fun component2():Int = age
}
data class Student2Data(var name:String,var age:Int)


fun main() {
   
    val (name,age) = Student("test",1111)
    println("解構(gòu):name=$name,age=$age")
    val (name1,age1) = Student2Data("test",1111)
    println("解構(gòu)2:name=$name1,age=$age1")
}

必須加入操作符標(biāo)記,否則復(fù)發(fā)接受自定義結(jié)構(gòu) operator fun component1():String = name

目的對(duì)比data class 解釋解構(gòu)的特性

操作符重栽,聯(lián)想c++

data class AddPlus(var num1:Int,var num2:Int){
    operator fun plus(p:AddPlus): Int {
        return (p.num1 +num1 + p.num2 + num2)
    }
    //AddPlus. 可以提示你可重新載入的操作符
    operator fun div(p:AddPlus):AddPlus{
        return AddPlus(num1+p.num1,num2 + p.num2)
    }
}

fun main() {
    println(AddPlus(1,1) + AddPlus(2,2))
//    val (a,b) = AddPlus(1,1) / AddPlus(2,2)
//    println("a,b,$a,$b")
    println(AddPlus(1,1) / AddPlus(2,2))
}

利用編譯器提示可用的操作符,AddPlus 加點(diǎn)就可以
用data class是為了輸出方便查看,直接class也是可以的

枚舉類(lèi)的使用和經(jīng)驗(yàn)
簡(jiǎn)單項(xiàng)目中狀態(tài)

enum class UIStateEnum constructor(v: Int) {
    //1,取消搜藏,2,搜藏,3,取消點(diǎn)贊,4,點(diǎn)贊,5 取消關(guān)注,6 關(guān)注,7,取消關(guān)注番劇 8,關(guān)注追番劇
    Undefined(0),
    CancelCollect(1),
    CollectState(2),
    UnLikeState(3),
    LikeState(4),
    UnFollowUser(5),
    FollowUser(6),
    UnFollowVideo(7),
    FollowVideo(8);

    var value = v
    override fun toString(): String {
        return "$value"
    }
}

    println(UIStateEnum.Undefined.value)
    println(UIStateEnum.Undefined.toString())

簡(jiǎn)單封裝一下使用

data class Info(var libinfo:String,var length:Int)

enum class LibInfo(var info: Info){
    L_HAND(Info("左手", 88)), // 左手
    R_HAND(Info("右手", 88)), // 右手

    L_FOOT(Info("左腳", 140)), // 左腳
    R_FOOT(Info("右腳", 140)) // 右腳
    ;

    fun show() = "四肢是:${info.libinfo}的長(zhǎng)度是:${info.length}"

    fun updateData(info: Info) {
        println("更新前的數(shù)據(jù)是:${this.info}")
        this.info.libinfo = info.libinfo
        this.info.length = info.length
        println("更新后的數(shù)據(jù)是:${this.info}")
    }

}

// 一般的用法如下:
    println(LibInfo.L_HAND.show())
    println(LibInfo.R_HAND.show())
    println(LibInfo.L_FOOT.show())
    println(LibInfo.R_FOOT.show())

    println()

    // 更新枚舉值
    LibInfo.R_HAND.updateData(Info("====右手22222222", 11))
    LibInfo.L_HAND.updateData(Info("====左手22222222", 11))
    LibInfo.L_FOOT.updateData(Info("====左腳222222", 199))
    LibInfo.R_FOOT.updateData(Info("====右叫222222", 199))

密封類(lèi)sealed class 使用
舉個(gè)我們九年義務(wù)教育和各種教育都用的例子??荚圏h委,我們只輸出優(yōu)秀學(xué)生的名字。

sealed class Exams{
    object Fun1:Exams()
    object Fun2:Exams()
    class Fun3(val name:String):Exams()
}

class Teachers(var exam:Exams){
    fun show() =
        when (exam) {
            is Exams.Fun1 -> "及格"
            is Exams.Fun2 -> "良好"
            is Exams.Fun3 -> "優(yōu)秀,學(xué)生名字是${(this.exam as Exams.Fun3).name}"
        }
}

fun main() {
    println(Teachers(Exams.Fun1).show())
    println(Teachers(Exams.Fun2).show())
    println(Teachers(Exams.Fun3("zhang san")).show())
    println(Teachers(Exams.Fun3("wang wu")).show())

    println(Exams.Fun1 === Exams.Fun1) // true, === 必須對(duì)象引用, object是單例 只會(huì)實(shí)例化一次

    println(Exams.Fun3("AAA") === Exams.Fun3("AAA")) // class 有兩個(gè)不同的對(duì)象,所以是false
}

這個(gè)有點(diǎn)想我們的枚舉,使用枚舉可以但是比較麻煩和難做。相似點(diǎn)都是代數(shù)數(shù)據(jù)模型。

解釋一下

1 限制枚舉每個(gè)類(lèi)型只允許有一個(gè)實(shí)例
2 限制所有枚舉常量使用相同的類(lèi)型的值
3 Sealed Classes 包含了抽象類(lèi)和枚舉的優(yōu)勢(shì):抽象類(lèi)表示的靈活性和枚舉常量的受限性
4 Sealed Classes 用于表示受限制的類(lèi)層次結(jié)構(gòu),從某種意義上說(shuō),Sealed Classes 是枚舉類(lèi)的擴(kuò)展
5 枚舉的不同之處在于,每個(gè)枚舉常量?jī)H作為單個(gè)實(shí)例存在,而 Sealed Classes 的子類(lèi)可以表示不同狀態(tài)的實(shí)例

Sealed Classes 用于表示層級(jí)關(guān)系-->子類(lèi)可以是任意的類(lèi), 數(shù)據(jù)類(lèi)、Kotlin 對(duì)象、普通的類(lèi),甚至也可以是另一個(gè) Sealed
Sealed Classes 受限制----> 必須在同一文件中,或者在 Sealed Classes 類(lèi)的內(nèi)部中使用,在Kotlin 1.1 之前,規(guī)則更加嚴(yán)格,子類(lèi)只能在 Sealed Classes 類(lèi)的內(nèi)部中使用

這里說(shuō)的不是十分準(zhǔn)確,能夠解釋為什么用Sealed比枚舉合適

data class使用場(chǎng)景

  1. 數(shù)據(jù)請(qǐng)求返回bean。
  2. 不允許sealed,abstract,inner,open的修飾
  3. 至少有一個(gè)主構(gòu)造參數(shù),并且必須用var,val修飾的
  4. 需要比較,copy,解構(gòu),toString方便的時(shí)候可以使用
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

  • 不重要的廢話 前段時(shí)間看了一遍《Programming Kotlin》,主要目的是想提高自己的英文閱讀能力,能力提...
    珞澤珈群閱讀 3,584評(píng)論 1 7
  • 1. 重點(diǎn)理解val的使用規(guī)則 引用1 如果說(shuō)var代表了varible(變量),那么val可看成value(值)...
    leeeyou閱讀 576評(píng)論 0 0
  • 1. 變量常量與類(lèi)型 聲明變量 常用類(lèi)型 變量類(lèi)型 例: 查看字節(jié)碼 雙擊Shift --> 輸入 show k...
    打工崽閱讀 415評(píng)論 0 2
  • 前言 人生苦多,快來(lái) Kotlin ,快速學(xué)習(xí)Kotlin! 什么是Kotlin? Kotlin 是種靜態(tài)類(lèi)型編程...
    任半生囂狂閱讀 26,750評(píng)論 9 118
  • 一、Kotlin基礎(chǔ) 1.1 變量 在Kotlin中變量分為可變引用var和不可變引用val,val對(duì)應(yīng)的是jav...
    東方未曦閱讀 612評(píng)論 0 1

友情鏈接更多精彩內(nèi)容