kotlin基礎(chǔ)學(xué)習(xí)-5(對(duì)象,繼承相關(guān))

  • 繼承與重載的關(guān)鍵字open
    類默認(rèn)都是封閉的,要想某個(gè)類開(kāi)放繼承,必須使用open關(guān)鍵字修飾它
在main函數(shù)中調(diào)用
    //繼承
    val carProduct : Product = CarProduct()
    println(carProduct.description())
    println(carProduct.load())

//繼承
open class Product(val name : String){
    fun description () = "Product === $name"

    open fun load () = "Loading..."
}

//繼承父類,父類必須用open關(guān)鍵字,否則默認(rèn)類是final
class CarProduct:Product("aodi"){
    //這里的override是關(guān)鍵字,重寫(xiě)某父類方法需要加override,并且父類方法必須聲明為open
    override fun load () ="aodi Loading..."

    fun carMethod() = "car special Method"
}
  • 類型轉(zhuǎn)換
    is as 關(guān)鍵字
    kotlin中的Any超類,類似于java中的object
//類型轉(zhuǎn)換
    println(carProduct is Product)
    println(carProduct is CarProduct)
    if(carProduct is CarProduct){
        println((carProduct as CarProduct).carMethod())
    }
  • 對(duì)象聲明
    使用object關(guān)鍵字,可以定義一個(gè)只能產(chǎn)生一個(gè)實(shí)例的類--單例
    使用object關(guān)鍵字有三種方式
    1.對(duì)象聲明
//在kotlin中,聲明一個(gè)類為單例很方便,直接使用object
object ApplicationConfig{
    init {
        println("applicationConfig init...")
    }

    fun doSomething(){
        println("doSomething")
    }
}

在main函數(shù)中調(diào)用
    //在kotlin中,聲明一個(gè)類為單例很方便,直接使用object
    ApplicationConfig.doSomething()//這里并不是說(shuō)是靜態(tài)的,而是聲明了是單例類,這里就可以直接使用類名作為對(duì)象名

    //指向的都是同一個(gè)對(duì)象,因?yàn)樗菃卫?    println(ApplicationConfig)
    println(ApplicationConfig)
    println(ApplicationConfig)

2.對(duì)象表達(dá)式

open class Player8 {
    open fun load() = "loading nothing"
}
在main函數(shù)中調(diào)用
    //對(duì)象表達(dá)式作為子類
    //類似于java中的new 一個(gè)OnclickListener,這個(gè)匿名類依然遵循object關(guān)鍵字的原則,一旦實(shí)例化,只能有唯一一個(gè)實(shí)例存在
    val p  = object : Player8(){
        override fun load() = "匿名類的loading方法"
    }
    println(p.load())

3.伴生對(duì)象

//伴生對(duì)象
open class SinggleTest{
    //只有初始化SinggleTest類或者調(diào)用load函數(shù)時(shí),伴生對(duì)象的內(nèi)容才會(huì)載入
    //而且無(wú)論實(shí)例化多少次,這個(gè)伴生對(duì)象始終只有一個(gè)實(shí)例存在。有點(diǎn)類似java的static
    //一個(gè)類里只能有一個(gè)伴生對(duì)象
    companion object{
        private const val PATH = "xxxxxxx"
        fun load() = println("伴生對(duì)象的方法執(zhí)行")
    }
}
在main函數(shù)中調(diào)用
    //伴生對(duì)象
    SinggleTest.load()
  • 嵌套類
//嵌套類(內(nèi)部類)
//如果一個(gè)類只對(duì)另一個(gè)類有用,那么將其嵌入到該類中并使兩個(gè)類保持在一起就很合邏輯,可以使用嵌套類
class Player1{
    class Equipment(var name:String){
        fun show() = println("equipment:$name")
    }
    fun battle() = println("ak47...")
}
在main函數(shù)中調(diào)用
    //嵌套類(內(nèi)部類)
    Player1.Equipment("天空套").show()
  • 數(shù)據(jù)類
    專門用來(lái)存儲(chǔ)數(shù)據(jù)的類
    看源碼可以看到,默認(rèn)實(shí)現(xiàn)了toString方法,打印的時(shí)屬性值
    ==符合默認(rèn)情況下,在any超類里面比較的是它們的引用值,數(shù)據(jù)類提供了equals和hashcode的個(gè)性化實(shí)現(xiàn),比較的是內(nèi)容
/**
 * 使用數(shù)據(jù)類的條件
 *  對(duì)于那些經(jīng)常需要比較,復(fù)制或打印自身內(nèi)容的類,數(shù)據(jù)類很適用。然而,一個(gè)類要成為數(shù)據(jù)類,也要符合一定條件,總結(jié)下來(lái),主要有三個(gè)方面
 *  1.數(shù)據(jù)類必須有至少帶一個(gè)參數(shù)的主構(gòu)造函數(shù)
 *  2.數(shù)據(jù)類主構(gòu)造函數(shù)的參數(shù)必須是var 或者 val
 *  3.數(shù)據(jù)類不能使用abstract,open,sealed和inner修飾符
 */
//數(shù)據(jù)類,用data關(guān)鍵字修飾
data class Coordinate(val x : Int,val y : Int){
}

在main函數(shù)中調(diào)用
    //這里打印的是Coordinate(x=1, y=2)。如果不用data修飾,打印的是Coordinate@60e53b93
    println(Coordinate(1,2))

    //這里結(jié)果是true,如果類名不用data修飾,則是false
    println(Coordinate(1,2) == Coordinate(1,2))
  • copy函數(shù)
//data數(shù)據(jù)類的copy函數(shù)demo
data class StudentOrigin(
    val name: String,
    var age : Int,
    var isNormal : Boolean
){
    var score = 0

    //次構(gòu)造函數(shù),有主就有次,我們可以定義多個(gè)次構(gòu)造函數(shù)來(lái)配置不同的參數(shù)組合
    constructor(_name: String) : this (_name,age = 10,isNormal = false){
        //copy函數(shù)不會(huì)調(diào)用這,copy出去的值還是0
        score = 10
    }


    //初始化塊,與java的static不一樣,這里的初始化塊是構(gòu)造函數(shù)執(zhí)行的時(shí)候,就會(huì)執(zhí)行初始化快
    init {
        //先決函數(shù),如果boolean值是false,執(zhí)行l(wèi)ambda拋出異常
        require(age > 0) {
            "age must be positive"
        }
        require(name.isNotBlank()){
            "student must have a name"
        }
    }

    override fun toString(): String {
        return "StudentOrigin(name='$name', age=$age, isNormal=$isNormal, score=$score)"
    }
}
在main函數(shù)中調(diào)用
    //copy函數(shù),它可以將數(shù)據(jù)類的其他屬性都copy過(guò)來(lái)。但是這里有一個(gè)坑,次構(gòu)造函數(shù)里面修改過(guò)的值不能copy,需要重新賦值
    val s = StudentOrigin("Jack")
    val copy = s.copy("Rose")
    println(s)
    println(copy)
  • 解構(gòu)聲明
//解構(gòu)語(yǔ)法的demo類
class Demo(val x:Int , val y : Int){
    //這里的component1等名字都是固定寫(xiě)法,不能修改
    operator fun component1() = x
    operator fun component2() = y
}
//數(shù)據(jù)類,用data關(guān)鍵字修飾
data class Coordinate(val x : Int,val y : Int){
}

在main函數(shù)中調(diào)用
    //數(shù)據(jù)類默認(rèn)支持解構(gòu)語(yǔ)法,如果不是數(shù)據(jù)類,則需要我們手動(dòng)在類里面重寫(xiě)方法,就如果解構(gòu)語(yǔ)法demo類一樣。
    val (x,y) = Coordinate(1,2)
    println("$x,$y")

    //解構(gòu)語(yǔ)法的demo類
    val (a,b) = Demo(3,4)
    println("$a,$b")
  • 運(yùn)算符重載
    使用operator關(guān)鍵字
/**
 * 運(yùn)算符重載,常見(jiàn)的操作符
 *
 *
 *  操作符                 函數(shù)名                 作用
 *  +                     plus                  把一個(gè)對(duì)象添加到另一個(gè)對(duì)象里
 *  +=                    plusAssign            把一個(gè)對(duì)象添加到另一個(gè)對(duì)象里,然后將結(jié)果賦值給第一個(gè)對(duì)象
 *  ==                    equals                如果兩個(gè)對(duì)象相等,則返回true,否則返回false
 *  >                     compareTo             如果左邊的對(duì)象大于右邊的對(duì)象,就返回true,否則返回false
 *  []                    get                   返回集合中指定位置的元素
 *  ..                    rangeTo               創(chuàng)建一個(gè)range對(duì)象
 *  in                    contains              如果對(duì)象包含在集合里,則返回true
 *
 */


data class Coordinate2(val x: Int,val y: Int){
    //運(yùn)算符重載,使用operator關(guān)鍵字
    operator fun plus(other:Coordinate2) = Coordinate2(x+other.x,y+other.y)
}
在main函數(shù)中調(diào)用
    //運(yùn)算符重載
    val coordinate2 = Coordinate2(10,50)
    val coordinate3 = Coordinate2(20,100)
    //如果下面的運(yùn)算符不重寫(xiě),這里使用+號(hào)就會(huì)報(bào)錯(cuò)
    println(coordinate2+coordinate3)
  • 枚舉類
    枚舉類也可以定義函數(shù)
data class Coordinate2(val x: Int,val y: Int){
    //運(yùn)算符重載,使用operator關(guān)鍵字
    operator fun plus(other:Coordinate2) = Coordinate2(x+other.x,y+other.y)
}

//枚舉類,也可以定義函數(shù)
enum class Direction(val coordinate:Coordinate2){
    EAST(Coordinate2(1,2)),
    WEST(Coordinate2(3,4)),
    NORTH(Coordinate2(5,6)),
    SOUTH(Coordinate2(7,8));

    fun updateCoordinate(other: Coordinate2) = Coordinate2(
        other.x + coordinate.x,
        other.y + coordinate.y
    )
}
在main函數(shù)中調(diào)用
    //枚舉類,用來(lái)定義常量集合的一種特殊類
    println(Direction.EAST) //輸出的就是枚舉的字符串值
    println(Direction.WEST.updateCoordinate(Coordinate2(10,20)))
  • 密封類
    密封類(sealed),從枚舉類思考更復(fù)雜的需求,比如我需要控制其中一個(gè)對(duì)象具有某種屬性,這時(shí)候使用密封類,但不要混淆,密封類不是枚舉
    密封類可以用來(lái)定義一個(gè)類似于枚舉類的類型,但是可以更靈活的控制某個(gè)子類型
    密封類可以有若干個(gè)子類,要繼承密封類,這些子類必須和它定義在同一個(gè)文件中
//密封類demo
class Driver(var status: LicenseStatus){
    fun checkLicense () : String {
        return when(status){
            is LicenseStatus.Unqualified -> "沒(méi)資格"
            is LicenseStatus.Learning -> "正在學(xué)"
            is LicenseStatus.Qualified -> "有資格,駕駛證編號(hào): " + (this.status as LicenseStatus.Qualified).licenseId
        }
    }

}

//密封類
sealed class LicenseStatus{
    object Unqualified : LicenseStatus()                             //這里沒(méi)有屬性,所以把它定義為單例
    object Learning : LicenseStatus()                                //這里沒(méi)有屬性,所以把它定義為單例
    class Qualified (var licenseId:String) : LicenseStatus()         //這里有一個(gè)id的屬性,所以不定義為單例
}
在main函數(shù)中調(diào)用
    println(Driver(LicenseStatus.Qualified("2820202")).checkLicense())
    println(Driver(LicenseStatus.Learning).checkLicense())
最后編輯于
?著作權(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)容