Android學(xué)習(xí)Kotlin之四、定義類(lèi)-初始化-繼承

Kotlin標(biāo)準(zhǔn)庫(kù)函數(shù)

定義一個(gè)類(lèi)很簡(jiǎn)單,和java一樣聲明需要的變量屬性,在kotlin中省略了get()和set()函數(shù)默認(rèn)支持get()和set(),并且可以自定義get()和set()函數(shù);初始化類(lèi)時(shí)順序很重要,如果代碼順序?qū)戝e(cuò)了會(huì)很容易報(bào)錯(cuò);類(lèi)通過(guò)open修飾可被繼承,和java不同的是kotlin的函數(shù)也需要通過(guò)open修飾后子類(lèi)才可以繼承。

Kotlin

其它Kotlin文章
Android學(xué)習(xí)Kotlin之一、常量-條件-函數(shù)-高階函數(shù)
Android學(xué)習(xí)Kotlin之二、Null安全 -字符串操作- 類(lèi)型轉(zhuǎn)換
Android學(xué)習(xí)Kotlin之三、標(biāo)準(zhǔn)庫(kù)函數(shù)-集合List-Set-Map
Android學(xué)習(xí)Kotlin之四、定義類(lèi)-初始化-繼承
Android學(xué)習(xí)Kotlin之五、對(duì)象-接口-抽象類(lèi)
Android學(xué)習(xí)Kotlin之六、泛型-擴(kuò)展函數(shù)

本編文章會(huì)講到的知識(shí)點(diǎn)

  • 定義類(lèi)
    • field
    • 計(jì)算屬性
  • 初始化類(lèi)
    • 主構(gòu)造函數(shù)使用臨時(shí)變量
    • 主構(gòu)造函數(shù)中直接定義屬性變量
    • 次構(gòu)造函數(shù)
    • 初始化塊
    • 初始化順序
    • 延遲初始化lateinit
    • 惰性初始化lazy
  • 繼承
    • open繼承
    • 類(lèi)型檢測(cè)
    • as智能轉(zhuǎn)換
    • Any類(lèi)

定義類(lèi)

field

針對(duì)你定義的每一個(gè)屬性,Kotlin都會(huì)產(chǎn)生-個(gè)field、一個(gè)getter、 以及一個(gè)setter, field用來(lái)存儲(chǔ)屬性數(shù)據(jù),你不能直接定義field, Kotlin會(huì)封裝 field,保護(hù)它里面的數(shù)據(jù),只暴露給getter和setter使用。屬性的getter方法決定你如何讀取屬性值,每個(gè)屬性都有g(shù)etter方法,setter方 法決定你如何給屬性賦值,所以只有可變屬性才會(huì)有setter方法,盡管Kotlin會(huì)自動(dòng)提供默認(rèn)的getter和setter方法,但在需要控制如何讀寫(xiě)屬性數(shù)據(jù)時(shí),你也可以自定義他們。

  • 定義一個(gè)Student類(lèi),里面定義變量,kotlin默認(rèn)提供的就有g(shù)et、set方法,也可以自定義get、set方法。
class Student {
    var name = "小明"
        get() = field.capitalize()
        set(value) {
            field = value.trim()//自定義set去除空格
        }
    var age = -12
        //自定義get和set函數(shù),實(shí)際根據(jù)自己需求來(lái)自定義get和set
        get() = field.absoluteValue//自定義取絕對(duì)值
        set(value) {
            field = value.absoluteValue
        }

    var adder:String? = "杭州"
}
  • 創(chuàng)建Student對(duì)象,調(diào)用屬性的get、set方法使用
 var student = Student()
    student.name = " 老王  "http://估計(jì)前后寫(xiě)空格
    println(student.name)//打印老王 沒(méi)有空格

    println(student.age)
    student.age = -6
    println(student.age)//打印 是正6 因?yàn)樽远xget中取絕對(duì)值了

    fun getAdder(){
        //如果adder不為空才會(huì)打印
        student?.adder?.also {
            println("地址=${it}")
        }
    }
    getAdder()
計(jì)算屬性

計(jì)算屬性是通過(guò)- -個(gè)覆蓋的get或set運(yùn)算符來(lái)定義,這時(shí)field就不需要 了。

    var value: Int? = null
        get() = (1..10).random()//自定義返回值get不使用field

    var student = Student()
    println(student.value)//返回1-10的隨機(jī)數(shù)

初始化類(lèi)

主構(gòu)造函數(shù)使用臨時(shí)變量

我們?cè)赥eacher類(lèi)的定義頭中定義一個(gè)主構(gòu)造函數(shù),使用臨時(shí)變量為T(mén)eacher的各個(gè)屬性提供初始值,在Kotlin中, 為便于識(shí)別,臨時(shí)變量(包括僅引用一-次的參數(shù)),通常都會(huì)以下劃線(xiàn)開(kāi)頭的名字命名。

 class Teacher(
    _name: String,
    _age: Int,
) {
    var name = _name
    var age = _age
    override fun toString(): String {
        return "Teacher(name='$name', age=$age)"
    }
}

    var teacher = Teacher("何炅", 50)
    println(teacher.name)//何炅
    println(teacher.toString())//Teacher(name='何炅', age=50)
打印.png
主構(gòu)造函數(shù)中直接定義屬性變量

Kotlin允許你不使用臨時(shí)變量賦值,而是直接用一個(gè)定義同時(shí)指定參數(shù)和類(lèi)屬性,通常,我們更喜歡用這種方式定義類(lèi)屬性,因?yàn)樗麜?huì)減少重復(fù)代碼。定義構(gòu)造函數(shù)時(shí),可以給構(gòu)造函數(shù)參數(shù)指定默認(rèn)值,如果用戶(hù)調(diào)用時(shí)不提供值參,就使用這個(gè)默認(rèn)值。

class Teacher2(
    var name: String,
    var age: Int = 10//可以設(shè)置默認(rèn)值
) {
    override fun toString(): String {
        return "Teacher2(name='$name', age=$age)"
    }
}

    var teacher2 = Teacher2("黃磊", 52)
    println(teacher2.name)//黃磊
    println(teacher2.toString())//Teacher2(name='黃磊', age=52)
次構(gòu)造函數(shù)

有主就有次,對(duì)應(yīng)主構(gòu)造函數(shù)的是次構(gòu)造函數(shù),我們可以定義多個(gè)次構(gòu)造函數(shù)來(lái)配置不同的參數(shù)組合,通過(guò)this指向把值傳遞給了主構(gòu)造函數(shù)??梢栽诖螛?gòu)造函數(shù)中進(jìn)行初始化代碼邏輯,比如修改參數(shù)值。

class Teacher3(
    var name: String,
    var age: Int,
) {
    //次構(gòu)造函數(shù) 通過(guò)this指向把值傳遞給了主構(gòu)造函數(shù)
    constructor(name:String):this(name,0){
        //這里可以進(jìn)行初始化代碼邏輯,給age賦值
        this.age = 18
    }
    override fun toString(): String {
        return "Teacher3(name='$name', age=$age)"
    }
}

    val teacher3 = Teacher3("黃曉明")//調(diào)用的是次構(gòu)造函數(shù) 沒(méi)有傳age值
    println(teacher3.toString())//Teacher3(name='黃曉明', age=18)
初始化塊

初始化塊可以設(shè)置變量或值,以及執(zhí)行有效性檢查, 如檢查傳給某構(gòu)造函數(shù)的值是否有效,初始化塊代碼會(huì)在構(gòu)造類(lèi)實(shí)例時(shí)執(zhí)行。

class Teacher4(
    var name: String,
    var age: Int,
) {
    init {
        println("${name} "+if (age>18) "滿(mǎn)18" else "未滿(mǎn)18")
        age = if (age > 18) 1 else 0 //判斷age的值 然后修改age的值
    }
    override fun toString(): String {
        return "Teacher4(name='$name', age=$age)"
    }
}

    var teacher4 = Teacher4("馬云",20)
    println(teacher4.toString())//Teacher4(name='馬云', age=1)
初始化順序

1.主構(gòu)造函數(shù)里聲明的屬性
2.類(lèi)級(jí)別的屬性賦值
3.init初始化塊里的屬性賦值和函數(shù)調(diào)用
4.次構(gòu)造函數(shù)里的屬性賦值和函數(shù)調(diào)用

class Teacher5(
    var name: String,
    var age: Int,
) {
    var hight: Int = 175

    init {
        println("初始化塊 ${name} " + if (age > 18) "滿(mǎn)18" else "未滿(mǎn)18")
    }

    constructor(name: String) : this(name, 10) {
        hight = 180
        println("這里是次構(gòu)造函數(shù)")
    }

    override fun toString(): String {
        return "Teacher5(name='$name', age=$age, hight=$hight)"
    }
}

    var teacher5 = Teacher5("小馬云")
    println(teacher5.toString())
初始化順序
延遲初始化lateinit
  • 只能用在var變量上;
  • 使用lateinit關(guān)鍵字相當(dāng)于做了一一個(gè)約定:在用它之前負(fù)責(zé)初始化;
  • 只要無(wú)法確認(rèn)lateinit變量是否完成初始化,可以執(zhí)行isInitialized檢查;

只能用在var變量上;該修飾只能用于類(lèi)體中(不是在主構(gòu)造函數(shù)中)聲明的var屬性,注意是var(可變屬性)并且僅當(dāng)該屬性沒(méi)有自定義getter或setter時(shí),該屬性必須是非空類(lèi)型,并且不能是原生類(lèi)型。

class Teacher6 {
    lateinit var name: String

    init {
        name = "中國(guó)驚奇先生"
    }

    fun getName() {
        if (::name.isInitialized) println(name) else println("name為空")
    }
}

    val teacher6 = Teacher6()
    teacher6.getName()
惰性初始化lazy
  • 只能用在val變量上

延遲初始化并不是推后初始化的唯一方式, 你也可以暫時(shí)不初始化某個(gè)變量,直到首次使用它,這個(gè)叫作惰性初始化。

class Teacher7 {
    val name: String by lazy {
        println("馬上賦值")
        "鎮(zhèn)魂街"
    }

    fun getName(){
        println(name)
    }
}
   val teacher7 = Teacher7()
    //第一次調(diào)用打印 “馬上賦值” “鎮(zhèn)魂街”
    teacher7.getName()
    //第二次調(diào)用只打印值,不會(huì)執(zhí)行l(wèi)azy{}過(guò)程
    teacher7.getName()

繼承

open繼承

默認(rèn)都是封閉的,要讓某個(gè)類(lèi)開(kāi)放繼承,必須使用open關(guān)鍵字修飾它。父類(lèi)的函數(shù)也要以open關(guān)鍵字修飾,子類(lèi)才能覆蓋它。

open class Animal(var name: String) {
    //父類(lèi)的函數(shù)也要以open關(guān)鍵字修飾,子類(lèi)才能覆蓋它。
    open fun getName() {
        println("this is ${name} ")
    }
}

class Cat : Animal("小狗") {
    override fun getName() {
//        super.getName()
        println("this2 is ${name} ")
    }
}

    val cat = Cat()
    println(cat.name)//小狗
    cat.getName()//this2 is 小狗 
類(lèi)型檢測(cè)

Kotlin的is運(yùn)算符是個(gè)不錯(cuò)的工具,可以用來(lái)檢查某個(gè)對(duì)象的類(lèi)型。

    val cat2 = Cat()
    println(cat2 is Cat)//true
    println(cat2 is Animal)//true
as智能轉(zhuǎn)換

as操作符聲明,這是一個(gè)類(lèi)型轉(zhuǎn)換。/為了避免拋出異常,可以使用安全轉(zhuǎn)換操作符 as?,它可以在失敗時(shí)返回 null。

    println(cat2 as Animal)
    var c = cat as Animal
//    var c1 = cat2 as Animal2//報(bào)錯(cuò) java.lang.ClassCastException
    var c1 = cat2 as? Animal2//為了避免拋出異常,可以使用安全轉(zhuǎn)換操作符 as?,它可以在失敗時(shí)返回 null
    println(c1)
    c?.getName()//this2 is 小狗
Any類(lèi)

無(wú)須在代碼里顯示指定,每一-個(gè)類(lèi)都會(huì)繼承一個(gè)共同的叫作Any的超類(lèi)。

    val cat = Cat()
    println(cat is Any)// true
    println(cat as Any)// com.example.kotlinjetpack.kotlin.Cat@66d3c617
最后編輯于
?著作權(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ù)。

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

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